"""
Copyright Alex Susu 2010-2012

  For iOS, iCam does not connect to the Internet automatically, so you need to 
connect to the Internet before starting the application.

  Tested only on iOS 3.1.2.
  This implies that UIKit allows taking photos, but not recording videos.
  However, the Cydia application Cycorder is able to record video even on iOS 3 
so we should investigate how to record video on iOS 3.
  Doing video recording on iOS 4+ is supported in the UIKit APIs, so this should
not raise considerable problems.

  To deploy the code, you need to generate the bytecode a.pyc file for this 
script (a.py) with any Python 2.5 and copy/replace it in /Applications/HelloPython.app/.

  Look for [!CHANGED_FROM_ORIGINAL!].
"""

CURRENT_RELEASE_TIME = "2012_05_27_13_00_00"

NUM_FRAMES_TO_UPDATE_VIEWFINDER_EVERY = 1 #10 #It seems that the main overhead is not the display but the storage, Inet transmission and maybe the detection algorithm.

startViewfinderBeforeTakingPhoto = 0 #1

ADD_VIDEO_TO_PLAYLIST = False

BATTERY_LEVEL_THRESHOLD = 99

#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
########################################PLATFORM DEPENDENT ISSUES######################################################
#######################################################################################################################
#######################################################################################################################
import os
import sys

SYMBIAN_OS = False
ANDROID_OS = False

try:
    import objc
    iOS_PYOBJC = True
except:
    #print "Couldn't import the android module."
    iOS_PYOBJC = False

if (ANDROID_OS == False):
    #We add lib_std.zip in the sys.path to be able to import the GData API library, which we install apriori in the current directory.
    #sys.path.insert(0, os.getcwd())
    #sys.path.insert(0, os.path.join(os.getcwd(), "gdata.zip"))
    if (iOS_PYOBJC):
        #So far, sys.path[0] was '/private/var/stash/Applications.k14UJu/HelloPython.app' and os.getcwd() returns "/". But I fear!!!! that this is not always like this.
        #sys.path.insert(0, os.path.join(sys.path[0], "lib_std.zip"))
        sys.path.append(os.path.join(sys.path[0], "lib_std.zip"))
    else:
        sys.path.insert(0, os.path.join(os.getcwd(), "lib_std.zip"))

    #print "sys.path = ", sys.path
    #sys.stdout.flush()


MY_DEBUG_STDOUT = True
MY_DEBUG_STDERR = True
MY_DEBUG_STDERR_2 = True
MY_DEBUG_UPLOAD_MSG = True #For uploaded log messages

MEGA_BYTE = 1024 * 1024

LOCAL_DRIVE = ""
LOCAL_FOLDER_TEMP = None

if (iOS_PYOBJC):
    #It seems /tmp is erased on iOS upon reboot :)
    #if os.path.exists("/tmp"):
    #    LOCAL_DRIVE = "/tmp"

    #The bigger drive is at /private/var which is sym-linked at /var (df -H reports: /dev/disk0s2           3.6G   287M   3.3G   9% /private/var)
    #Note: the CameraRoll stores photos in /var/mobile/Media/DCIM/100APPLE/
    if os.path.exists("/var/mobile"):
        LOCAL_DRIVE = "/var/mobile"
    else:
        #It seems I don't have access to create "/iCam"!!!!
        LOCAL_DRIVE = "/"


LOCAL_FOLDER = LOCAL_DRIVE + "/iCam"
if (LOCAL_FOLDER_TEMP == None):
    LOCAL_FOLDER_TEMP = LOCAL_FOLDER
LOCAL_FOLDER_MEDIA_FILES = LOCAL_FOLDER + "/Media"
LOCAL_FOLDER_SENT_LOGS = LOCAL_FOLDER + "/LogsSent"

ERASE_ORIGINAL_MEDIA_FILE_AFTER_READ = False

LOCAL_FOLDER_UNSENT_FILES = LOCAL_FOLDER + "/Unsent"
STATE_FILENAME = LOCAL_FOLDER + "/state.bin"
STATE_LOCAL_FILENAME = LOCAL_FOLDER + "/" + "iCam.cfg" #"local.bin"
BACKUP_EXTENSION = ".bak"
STATE_FILENAME_BACKUP = STATE_FILENAME + BACKUP_EXTENSION

STDERR_FILENAME_PREFIX = "stderr_"
STDOUT_FILENAME_PREFIX = "stdout_"

PHP_SERVER_NAME = "mobile-revival.110mb.com"
WEB_FOLDER = "/ReVival"

WEBPAGE_UL_GZIPPED_STATE_AND_FILE = WEB_FOLDER + "/UploadGzippedStateAndFile.php"
WEBPAGE_UL_GZIPPED_STATE_AND_FILE_PROXY_YOUTUBE = "/proxyyoutube"
WEBPAGE_UL_GZIPPED_FILE = WEB_FOLDER + "/UploadFile.php"
WEBPAGE_DL_GZIPPED_FILE = WEB_FOLDER + "/DownloadFile.php"
WEBPAGE_UL_GZIPPED_TEXT = WEB_FOLDER + "/UploadGzippedText.php"
WEBPAGE_DL_COMMAND_FILE = WEB_FOLDER + "/cmd.php"

BT_OBEX_FILENAME_PREFIX = "iCam_"
BT_OBEX_FILENAME_PREFIX_TYPE_TEXT = "TXT_"
BT_OBEX_FILENAME_PREFIX_TYPE_SMF  = "SMF_"
BT_OBEX_FILENAME_PREFIX_TYPE_CMD  = "CMD_"
BT_OBEX_FILENAME_PREFIX_TYPE_FILE = "FIL_"
COMMANDS_FILENAME = "cmd.txt"
EXTENSION_TEXT_MESSAGE = ".txm" #Text message.
EXTENSION_STATE_AND_MEDIA_FILE = ".smf" #"smf" comes from state and media file. These files are used for Unsent (own files and for Bluetooth client).
EXTENSION_ARBITRARY_FILE = ".fil" #"fil" comes from arbitrary file - used for Unsent, Bluetooth, etc

conserveEnergy = False
saveUnsentPackets = 0 #0 - None, 1 - All; 2 - wo .txm
uploadUnsentData = 0 #0 - send none; 1 - send unsent files from Unsent (excepting .txm unsent files); 2 - send unsent logs; 3 - send ALL (excepting .txm  unsent files)
NUM_UNSENT_PACKETS_BEFORE_DOWNLOAD_COMMANDS = 1 #10

logAccelerometerAndRotationSensors = False
startAutomatically = 0 #False
startButtonPressed = False
reactiveLoopIsStarted = False

bluetoothServerOPPServicePort = -1


#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
###########################################STATE VARIABLES#############################################################
#######################################################################################################################
#######################################################################################################################

import time
import traceback


NO_GSM_SIGNAL_STRENGTH = -1234 #this is for the case when there is no SIM card in the cellphone
signalStrength = NO_GSM_SIGNAL_STRENGTH
signalUnits = ""
accessPointName = u""
accessPointNotConnectedTo = False #If accessPointNotConnectedTo is True it means that connection to the AP accessPointName was not successful. And this leads to retrying connection to the AP.

def NoInternetConnection():
    global accessPointName, accessPointNotConnectedTo
    return ((accessPointNotConnectedTo == True) or (accessPointName == u""))


def DisplayNote(aText, waitTime = 2.0):
    pass

def DialogGetInput(aText, aTextMore, aInitVal):
    resStr = None
    return resStr


if (iOS_PYOBJC):
    import subprocess
def GetDeviceId():
    if (iOS_PYOBJC):
        try:
            if (MY_DEBUG_STDOUT):
                print "GetDeviceId(): calling subprocess.call()."
                sys.stdout.flush()
            #See http://stackoverflow.com/questions/6441807/spawn-a-new-non-blocking-process-using-python-on-mac-os-x (also http://stackoverflow.com/questions/2260614/how-to-switch-to-a-python-subprocess-created-by-ipython-on-os-x)
            #subprocess.call(["/Applications/pyExamp.app/pyExamp", "", ""]) #, stdout = None, stderr = fOutput) #Nothing happens.
            #subprocess.call(["/Applications/pyExamp.app/pyExamp"]) #, stdout = None, stderr = fOutput)
            #os.system("/Applications/pyExamp.app/pyExamp")

            #fOutput = open("/var/mobile/iCam/IMEI.txt", "wb")
            fOutput = open(LOCAL_FOLDER + "/IMEI.txt", "wb")
            #subprocess.call(["/var/14/deviceinfo", "-i"], stdout = fOutput, stderr = None) #fOutput)
            #subprocess.call([LOCAL_FOLDER + "/deviceinfo", "-i"], stdout = fOutput, stderr = None)
            subprocess.call([sys.path[0] + "/deviceinfo", "-i"], stdout = fOutput, stderr = None)
            fOutput.close()
        except:
            traceback.print_exc()
            sys.stderr.flush()

        #threading.Timer(0.1, ExecProcess).start()
        #thread.start_new_thread(ExecProcess, ())
        #ExecProcess()

        try:
            fInput = open(LOCAL_FOLDER + "/IMEI.txt", "r")
            myRes = fInput.read()
            fInput.close()
            """
            if (MY_DEBUG_STDOUT):
                print "GetDeviceId(): (before) myRes = %s" % myRes
                sys.stdout.flush()
            """
            myRes = myRes.rstrip(" \r\n")
            """
            if (MY_DEBUG_STDOUT):
                print "GetDeviceId(): (after) myRes = %s" % myRes
                sys.stdout.flush()
            """
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()
            myRes = "iPhone-device-id"

        return myRes
deviceId = GetDeviceId() #sysinfo.imei() returns unicode string, so we convert it to ASCII string

localPhotoResolution = None
localVideoMode = None
modeManagerIsEnabled = False

burstModeIsStarted = False
#Burst mode take as many frames as possible per second when the viewfinder is on. This happens when pauseInterval == 0.
motionDetectionIsOn = False
#motionDetectionIsOn = True #Detect simple changes in images.

VIEWFINDER_SIZE_ORIG = (-1, -1)
viewFinderSize = VIEWFINDER_SIZE_ORIG

readGPS = 0 #False
gpsInfo = {"position": {}, "course" : {}, "satellites" : {}}

numCamerasSupported = 2 #We assume 2 cameras by default.

#The default configuration for the application.
#pauseInterval represents the interval of time the system waits between media capture actions (video recordings, take photos).
#NOT USED: pauseInterval represents the interval of time the system waits in a Reactive loop.
pauseInterval = 120 #2 minutes
pauseIntervalBetweenGoogleGdataMediaUploads = 60

digitalZoom = 0 #no zoom
photoResolutionIndex = 6 #320x240
photoModeIndex = [3, 2] #JPEG_Exif, RGB24
photoQuality = 50 #50% quality
exposureIndex = [0] * 2
whiteBalanceIndex = [0] * 2
flashIndex = 1
audioRecordDuration = 0
videoRecordDuration = [30, 30] #[0, 0] #[0, 7]
rotateDegreesImage = 0
localQualityIndex = 0
localPhotoResolutionIndex = [None, None]
cameraMode = [1, 0] #0 = None, 1 = Only Video, 2 = Only Photo, 3 = Both Photo and Video
if (iOS_PYOBJC == True): #Currently cannot record video on iOS
    cameraMode = [2, 0]
videoAudioEnabled = 1 #True #False
localVideoModeIndex = [0, 0] #[None, None]
storeLocallyMedia = 1 #0 = no local storage; 1 = store all media (on SD card); in the future, we should have other values as well (e.g., 2 = store only movies, but not photos)
orientationForThisPhoneModel = "landscape"

mobileCountryCode = -1
mobileNetworkCode = -1
locationAreaCode = -1
cellId = -1

phoneModel = ""

#We can use lookup after deviceId to get the phoneNumber
phoneNumber = "no_phone_number"

bluetoothMode = 0 #0 is None; 1 is BT server;2 is BT client;
bluetoothServerAddress = ""
bluetoothSelfAddress = ""
bluetoothSelfName = ""

cameraPhotoSizes_JPEG_Exif = [None, None]
cameraPhotoSizes_RGB24 = [None, None]

cameraVideoFormats = [None, None]
cameraVideoFrameSizes = [None, None]
cameraVideoModes = [None, None]

myMaxRamdriveSize = -1

#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
###########################################END STATE VARIABLES#########################################################
#######################################################################################################################
#######################################################################################################################

################################################SETTINGS FOR MY PHONES#################################################

INTERNET_PROXY_PHONE_DEVICE_ID = "300300300300300" #This is the master in a BT network
INTERNET_PROXY_PHONE_BLUETOOTH_ADDRESS = "00:1d:fd:78:d7:8a"


#CreateDirectoriesAndLogFiles()

#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
###############################################IMPORTS#################################################################
#######################################################################################################################
#######################################################################################################################

import thread
import zlib


def MyThreadStart(myFunc):
    thread.start_new_thread(myFunc, ())


"""
I put this code here because I want to create ASAP the log files and see in the log files any error generated by importing spcecial modules, etc.
Unfortunately, there is no other way - see for ex. http://stackoverflow.com/questions/1590608/is-it-possible-to-forward-declare-a-function-in-python.
#!!!!For nicer code I should put GetCurrentDateTime() and CreateDirectoriesAndLogFiles() in a separate module and import it here.
"""
def GetCurrentDateTime(): #The type of this one is a struct? localtime
    if (iOS_PYOBJC):
        return time.localtime()


stdoutFile = None
stderrFile = None
stdoutFileName = None
stderrFileName = None
def CreateDirectoriesAndLogFiles():
    global stdoutFile, stderrFile
    global stdoutFileName, stderrFileName
    global LOCAL_FOLDER, LOCAL_FOLDER_MEDIA_FILES, LOCAL_FOLDER_UNSENT_FILES
    global STATE_FILENAME

    STATE_FILENAME = LOCAL_FOLDER + "/state.bin"

    try:
        """
        !!!!Check also that these folders are not files with isfile()...
        """
        if not os.path.exists(LOCAL_FOLDER):
            os.makedirs(LOCAL_FOLDER)
        if not os.path.exists(LOCAL_FOLDER_MEDIA_FILES):
            os.makedirs(LOCAL_FOLDER_MEDIA_FILES)
        #Note: On WinCE normally the Unsent media files are stored in .../DCIM
        if not os.path.exists(LOCAL_FOLDER_UNSENT_FILES):
            os.makedirs(LOCAL_FOLDER_UNSENT_FILES)
        if not os.path.exists(LOCAL_FOLDER_TEMP):
            os.makedirs(LOCAL_FOLDER_TEMP)

        STDDateTime = time.strftime("%Y_%m_%d_%H_%M_%S", GetCurrentDateTime())
        if (MY_DEBUG_STDOUT):
            sys.stdout.flush()
            """
            """
            #if (deviceId != "357062005806103"): #Nokia 6680 has little space (drive C - ~3MB) since it does not have an RS-MMC broke, so we can't store the long stdout log files.
            stdoutFileName = STDOUT_FILENAME_PREFIX + STDDateTime + ".txt"
            stdoutFile = open(LOCAL_FOLDER + "/" + stdoutFileName, "a")
            sys.stdout = stdoutFile
            sys.stdout.flush()

        if (MY_DEBUG_STDERR):
            sys.stderr.flush()
            stderrFileName = STDERR_FILENAME_PREFIX + STDDateTime + ".txt"
            stderrFile = open(LOCAL_FOLDER + "/" + stderrFileName, "a")
            sys.stderr = stderrFile
            sys.stderr.flush()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
CreateDirectoriesAndLogFiles()

if (MY_DEBUG_STDOUT):
    print "sys.path = ", sys.path
    sys.stdout.flush()

import struct
import httplib
"""
#Need to include it in lib(_std).zip, since it is not a standard library.
try:
    import httplib2
    import urllib3
except:
    if (MY_DEBUG_STDERR):
        traceback.print_exc()
        sys.stderr.flush()
"""
import urllib


try:
    import socket
except:
    if (MY_DEBUG_STDOUT):
        print "Not able to import the socket module."
        sys.stdout.flush()
    if (MY_DEBUG_STDERR):
        traceback.print_exc()
        sys.stderr.flush()

"""
To have socket timeout on PyS60 1.4.5 see for ex http://discussion.forum.nokia.com/forum/showthread.php?72774-socket-timeout
Use maybe Tsocket extension - see also http://discussion.forum.nokia.com/forum/showthread.php?109520-announce-tsocket-socket-module-timeout-on-connect.
"""
SOCKET_DEFAULT_TIMEOUT = 20.0
#SOCKET_DEFAULT_TIMEOUT = 10.0
#socket.setdefaulttimeout(5.0) - gives many timeouts, at least when the server was down
try:
    #Inspired from https://groups.google.com/group/comp.lang.python/browse_thread/thread/ff84e7340988c168/
    #socket.setdefaulttimeout(5.0)
    """
    From http://docs.python.org/library/socket.html#socket.setdefaulttimeout: "A value of None indicates that new socket objects have no timeout. When the socket module is first imported, the default is None." 
    Also note that on Windows it seems that the default timeout is 20-30 seconds.
    """
    socket.setdefaulttimeout(SOCKET_DEFAULT_TIMEOUT)
except:
    if (MY_DEBUG_STDOUT):
        print "Not able to use socket.setdefaulttimeout() - maybe because running on PyS60 1.4.5."
        sys.stdout.flush()
    if (MY_DEBUG_STDERR):
        traceback.print_exc()
        sys.stderr.flush()

#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
#############################################END IMPORTS###############################################################
#######################################################################################################################
#######################################################################################################################

#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
###############################################STRINGS#################################################################
#######################################################################################################################
#######################################################################################################################
#See http://www.daniweb.com/forums/thread138449.html and http://bytes.com/topic/python/answers/768072-nameerror-global-name-addbook-not-defined
pauseIntervalStr = [
            ["0 sec (Burst mode)",  0],
            ["1 sec",     1],
            ["5 sec",     5],
            ["10 sec",   10],
            ["15 sec",   15],
            ["20 sec",   20],
            ["30 sec",   30],
            ["45 sec",   45],
            ["1 min",    60],
            ["2 min",   120],
            ["3 min",   180],
            ["4 min",   240],
            ["5 min",   300],
            ["7 min",   420],
            ["10 min",  600],
            ["15 min",  900],
            ["20 min", 1200],
            ["30 min", 1800],
            ["45 min", 2700],
            ["50 min", 3000],
            ["1 hr",   3600],
            ["2 hr",   7200],
            ["3 hr",  10800],
            ["4 hr",  14400],
            ["5 hr",  18000],
            ["6 hr",  21600],
            ["10 hr", 36000],
            ["12 hr", 43200],
            ["24 hr", 86400]
        ]
photoResolutionStr = [
            ["Do Not Upload Photo",   (0,  0)],
            ["Use Local Resolution", (-1, -1)],
            [  "40x30",            (40,   30)],
            [  "80x60",            (80,   60)],
            [ "160x120",          (160,  120)],
            [ "240x180",          (240,  180)],
            [ "320x240",          (320,  240)],
            [ "512x384",          (512,  384)],
            [ "640x480",          (640,  480)],
            ["1152x864",         (1152,  864)],
            ["1280x960",         (1280,  960)],
            ["1600x1200",        (1600, 1200)],
            ["2048x1536",        (2048, 1536)],
            ["2592x1456",        (2592, 1456)],
            ["2592x1944",        (2592, 1944)],
            ["3264x1832",        (3264, 1832)],
            ["3264x2448",        (3264, 2448)],
            ["4000x2248",        (4000, 2248)],
            ["4000x3000",        (4000, 3000)]
        ]
photoModeStr = [
                ["RGB12" ,        "RGB12"],
                ["RGB16" ,        "RGB16"],
                ["RGB24" ,          "RGB"],
                ["JPEG_Exif", "JPEG_Exif"],
                ["JPEG_JFIF", "JPEG_JFIF"]
            ]
flashStr = [
                ["Auto",           "auto"],
                ["None",           "none"],
                ["Red_eye_reduce", "red_eye_reduce"],
                ["Forced",         "forced"],
                ["Fill_in",        "fill_in"]
        ]

exposureStr = [ 
                ["Auto",      "auto"],
                ["Center",    "center"],
                ["Backlight", "backlight"],
                ["Night",     "night"]
        ]

whiteBalanceStr = [ 
                    ["Auto",        "auto"],
                    ["Daylight",    "daylight"],
                    ["Cloudy",      "cloudy"],
                    ["Tungsten",    "tungsten"],
                    ["Fluorescent", "fluorescent"],
                    ["Flash",       "flash"]
        ]
#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
#############################################END STRINGS###############################################################
#######################################################################################################################
#######################################################################################################################


#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
##########################################MOTION DETECTION#############################################################
#######################################################################################################################
#######################################################################################################################

differentPixelsPercentage = 10
MAX_NUM_HOTSPOTS = 5
hotspot = []
for i in range(MAX_NUM_HOTSPOTS):
    hotspot += [ [ [0, 0], [0, 0] ] ]


def SetMotionDetectionHotspot(hotspotIndex, percentsUL_X, percentsUL_Y, percentsLR_X, percentsLR_Y):
    global hotspot, MAX_NUM_HOTSPOTS

    if (hotspotIndex >= MAX_NUM_HOTSPOTS):
        return

    hotspot[hotspotIndex][0][0] = percentsUL_X / 100.0
    hotspot[hotspotIndex][0][1] = percentsUL_Y / 100.0
    hotspot[hotspotIndex][1][0] = percentsLR_X / 100.0
    hotspot[hotspotIndex][1][1] = percentsLR_Y / 100.0


SetMotionDetectionHotspot(0, 0.0, 0.0, 100.0, 100.0)
SetMotionDetectionHotspot(1, 50.0, 50.0, 80.0, 80.0)


"""
numHotspots = 1
differentPixelsPercentageThreshold = [5.0]
"""
#numHotspots = 2
numHotspots = 1
differentPixelsPercentageThreshold = [5.0, 10.0]
sizeMotionCheckWindow = (40, 30)
def DetectMotion(prevVFFrame, crtVFFrame):
    #See http://wiki.forum.nokia.com/index.php/Motion_detection_with_camera
    global numHotspots, hotspot, differentPixelsPercentageThreshold, sizeMotionCheckWindow

    #for hotspotIndex in range(0, numHotspots):
    for hotspotIndex in range(numHotspots):
        crtWidth, crtHeight = crtVFFrame.size
        #Draw a red rectangle.
        #crtVFFrame.rectangle([ (hotspot[hotspotIndex][0][0] * crtWidth, hotspot[hotspotIndex][0][1] * crtHeight), (hotspot[hotspotIndex][1][0] * (crtWidth - 1), hotspot[hotspotIndex][1][1] * (crtHeight - 1))], 0xff0000)
        #crtVFFrame.rectangle([ (hotspot[hotspotIndex][0][0] * crtWidth, hotspot[hotspotIndex][0][1] * crtHeight), (hotspot[hotspotIndex][1][0] * (crtWidth - 1), hotspot[hotspotIndex][1][1] * (199 - 1))], 0xff0000)
        crtStepX = int(crtWidth / sizeMotionCheckWindow[0])
        crtStepY = int(crtHeight / sizeMotionCheckWindow[1])
        #differentPixelsThreshold = crtWidth * crtHeight * differentPixelsPercentageThreshold[hotspotIndex] / 100.0
        differentPixelsThreshold = sizeMotionCheckWindow[0] * sizeMotionCheckWindow[1] * differentPixelsPercentageThreshold[hotspotIndex] / 100.0
        numDifferentPixels = 0
        #!!!!Use xrange - should lower down mem consumption - but what about performance?!!!!
        for y in range( int(hotspot[hotspotIndex][0][1] * crtHeight), int(hotspot[hotspotIndex][1][1] * (crtHeight - 1)), crtStepY):
            for x in range( int(hotspot[hotspotIndex][0][0] * crtWidth), int(hotspot[hotspotIndex][1][0] * (crtWidth - 1)), crtStepX):
                r, g, b = crtVFFrame.getpixel( (x, y) )[0]
                prevr, prevg, prevb = prevVFFrame.getpixel( (x, y) )[0]
                delta = abs(r - prevr) + abs(g - prevg) + abs(b - prevb)
                if (delta > 3 * 10): #3 * 30):
                    numDifferentPixels += 1
                    if (numDifferentPixels > differentPixelsThreshold): #40
                        if (MY_DEBUG_STDOUT):
                            print "DetectMotion(): detected motion - numDifferentPixels = %d > differentPixelsThreshold = %d." % (numDifferentPixels, int(differentPixelsThreshold))
                            sys.stdout.flush()
                        return True
                #From http://discussion.forum.nokia.com/forum/showthread.php?114751-Is-there-a-setpixel-for-image-objects (a bit also http://discussion.forum.nokia.com/forum/showthread.php?120004-How-to-access-pixel-array-of-image-captured-by-viewfinder)
                #crtVFFrame.point( (x, y), newRGB )

    if (MY_DEBUG_STDOUT):
        print "DetectMotion(): did NOT detect motion - numDifferentPixels = %d <= differentPixelsThreshold = %d." % (numDifferentPixels, int(differentPixelsThreshold))
        sys.stdout.flush()
    return False
    """
    im = camera.take_photo('RGB', (320,240)) #before it was 160 x 120 ; (1152, 864)
    im.rectangle([(10,10),(40,40)], 0xff0000)   # red outline
    im.rectangle([(120,10),(150,40)], 0xff0000) # no code for this square

    # check hot spot whether active
    box = Image.new((30,30), 'L')  # gray scale
    box.blit(im, (10,10,40,40))
    data = getdata(box, 8)

    # check difference for motion
    pixdiff = 0
    for x,y in zip(data, last1):
        if abs(ord(x)-ord(y)) > 15:  # pix threshold 15/256
            pixdiff += 1
            if pixdiff > 90:    # img threshold 90/900
                im.rectangle([(10,10),(40,40)], fill=0xff0000)  # fill
                break           # motion detected
    last1 = data
    c.blit(im, (0,0), (8,12))   # show camera
    #miso.reset_inactivity_time()
    """

#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
########################################END MOTION DETECTION###########################################################
#######################################################################################################################
#######################################################################################################################

def RestartPhone():
    if (iOS_PYOBJC):
        #Restarts the springboard
        subprocess.call(["/usr/bin/restart"]) #, stdout = fOutput, stderr = None)
        #Reboots
        #/sbin/reboot
        #pass


#####################################################################################################
#####################################################################################################
######More info about firmware types: Z:\1PhD\ReVival\1111PyS60_extensions\cyke642\firmware.py#######
#####################################################################################################
#####################################################################################################
def GetPhoneModel():
    modelName = ""
    if (iOS_PYOBJC):
        modelName = "iPhone-model"
    return modelName


def GetCurrentDateTimeStringWithMilliseconds():
    crtTime = GetCurrentDateTime()
    crtTime2 = time.time()
    numMilliseconds = (crtTime2 - int(crtTime2)) * 1000 #See http://discussion.forum.nokia.com/forum/showthread.php?116978-What-is-the-time-granularity-in-Pys60 .
    #fileName = time.strftime("%Y_%m_%d_%H_%M_%S", crtTime) + ("_%03d%s" % (numMilliseconds, fileExtension))
    return time.strftime("%Y_%m_%d_%H_%M_%S", crtTime) + ("_%03d" % numMilliseconds)


def GetCurrentDateTimeStringNice():
    """
    crtTime = GetCurrentDateTime()
    return time.strftime("%Y_%m_%d_%H_%M_%S", crtTime) + ("_%03d" % numMilliseconds)
    """
    #time.asctime(GetCurrentDateTime())
    return time.strftime("%H:%M:%S %d-%m-%Y", GetCurrentDateTime())


def isNaN(x):
    return (type(x) is float) and (x != x)

def isFinite(x):
    return x != Infinity


def GetGSMLocation():
    global mobileCountryCode, mobileNetworkCode, locationAreaCode, cellId

    if (iOS_PYOBJC):
        mobileCountryCode = -1
        mobileNetworkCode = -1
        locationAreaCode = -1
        cellId = -1


#http://discussion.forum.nokia.com/forum/showthread.php?p=743894#post743894
#and http://snippets.dzone.com/posts/show/831
#See also http://discussion.forum.nokia.com/forum/showthread.php?202489-e32.Ao_timer%28%29.after%28...%29-crashes-for-more-than-30-minutes
def LongAfter(aTimer, duration, callback):
    #The PyS60 timer has a limitation: it can wait for at most 2147 seconds. Therefore, we need to do a series of after to sleep with after() for longer.
    MAX_DURATION_ALLOWED_FOR_AFTER = 2100 #seconds

    while (duration > 0):
        if (duration > MAX_DURATION_ALLOWED_FOR_AFTER):
            aTimer.after(MAX_DURATION_ALLOWED_FOR_AFTER)
            duration -= MAX_DURATION_ALLOWED_FOR_AFTER
        else:
            aTimer.after(duration, callback)
            duration = 0


if (iOS_PYOBJC):
    MAX_DURATION_BETWEEN_PETTING = 30 #seconds
def SleepAndPetWatchdog(duration, powerManage = False):
    global sleepAndPetWatchdogTimer, pauseInterval
    global MAX_DURATION_BETWEEN_PETTING
    global modeManagerIsEnabled

    #duration = pauseInterval

    if (powerManage):
        if (modeManagerIsEnabled):
            ModeManager()
        duration = PowerManager() #This basically makes duration = pauseInterval (or 10 hours if the charger is not charging).

    try:
        while (duration > 0):
            if (duration > MAX_DURATION_BETWEEN_PETTING):
                if (iOS_PYOBJC):
                    if (MY_DEBUG_STDOUT):
                        print "SleepAndPetWatchdog(): Before time.sleep() - MAX_DURATION_BETWEEN_PETTING = %d." % (MAX_DURATION_BETWEEN_PETTING)
                        sys.stdout.flush()
                    time.sleep(MAX_DURATION_BETWEEN_PETTING) #It crashes app when MAX_DURATION_BETWEEN_PETTING = 30, around the middle, I guess.
                    #time.sleep(1)
                    if (MY_DEBUG_STDOUT):
                        print "SleepAndPetWatchdog(): finished time.sleep()."
                        sys.stdout.flush()
                duration -= MAX_DURATION_BETWEEN_PETTING
                pauseIntervalOld = pauseInterval
                PetWatchdog()

                """
                !!!!THIS DOESN'T WORK WELL IF pauseInterval is big (e.g., 1 hour, etc).
                In case the charger is powered after being stopped and we made duration very big (to sleep a lot), we stop sleeping.
                Also, this helps in case we change from (very) big pauseInterval to a smaller pauseInterval by stopping the sleep.
                """
                if (powerManage):
                    if (duration > PowerManager()):
                        return
                """
                if (pauseInterval < pauseIntervalOld): #In case the PowerManager decides to make pauseInterval shorter.
                    return
                """

                #if (durationOriginal - duration % MAX_DURATION_BETWEEN_PETTING == )pauseInterval 
                if (bluetoothMode == 2): #For BT client devices we should receive only BT messages with commands (CMD), so this should take very little time.
                    BluetoothMessageListProcess()
            else:
                duration = 0
                PetWatchdog()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


#Returns the amount of free RAM in bytes.
def GetFreeRAM():
    if (iOS_PYOBJC):
        return 123456789


#Returns the number of free bytes on the drive aDriveStr.
def GetFreeDriveSpace(aDriveStr):
    if (iOS_PYOBJC):
        return -1
    """
    MacOS (probably UNIX):
    #From http://stackoverflow.com/questions/787776/find-free-disk-space-in-python-on-os-x (see also http://ubuntuforums.org/showthread.php?t=961505):
    s = os.statvfs('/')
    print (s.f_bavail * s.f_frsize) / 1024
    """


AT_LEAST_FREE_DRIVESPACE_TO_STOP = 100 * 1024 * 1024
def EraseOldestFilesFromFolder(aFolder, atLeastFreeDrivespaceToStop):
    if (GetFreeDriveSpace(aFolder[:2]) >= atLeastFreeDrivespaceToStop):
        return

    try:
        if (MY_DEBUG_STDOUT):
            print "EraseOldestFilesFromFolder(): aFolder = %s" % aFolder
            sys.stdout.flush()

        mediaFolderContent = os.listdir(aFolder)
        #sortedMediaFolderContent = sorted(mediaFolderContent)
        mediaFolderContent.sort() #sort() without parameters is the ONLY one that works in Python 2.2. (Info on sort at http://wiki.python.org/moin/HowTo/Sorting/.)
        sortedMediaFolderContent = mediaFolderContent

        #print "sortedMediaFolderContent =", sortedMediaFolderContent

        for mediaFileName in sortedMediaFolderContent:
            pathFileName = aFolder + "/" + mediaFileName
            if (os.path.isfile(pathFileName)):
                """
                os.unlink(pathFileName)
                """
                if (MY_DEBUG_STDOUT):
                    print "EraseOldestMediaFiles(): deleting file %s." % pathFileName
                    sys.stdout.flush()
                if (GetFreeDriveSpace(aFolder[:2]) >= atLeastFreeDrivespaceToStop):
                    return
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def EraseOldestFilesAndMessages():
    if (MY_DEBUG_STDOUT):
        print "Entered EraseOldestFilesAndMessages()."
        sys.stdout.flush()
    EraseOldestFilesFromFolder(LOCAL_FOLDER_MEDIA_FILES, AT_LEAST_FREE_DRIVESPACE_TO_STOP) #Media - for test "."
    EraseOldestFilesFromFolder(LOCAL_FOLDER_UNSENT_FILES, AT_LEAST_FREE_DRIVESPACE_TO_STOP) #Unsent - for test use "O:\\!\\N82\\Media"
    #Erase BT messages!!!!


def DisplayDeviceId(*args):
    global deviceId

    if (MY_DEBUG_STDOUT):
        print "Entered DisplayDeviceId()."
        sys.stdout.flush()


def SelectAccessPointIfNoneAvailableAndConnectToIt():
    global accessPointName, accessPointNotConnectedTo

    if (iOS_PYOBJC):
        accessPointName = u"[DEFAULT_AP]"
        accessPointNotConnectedTo = False #If accessPointNotConnectedTo is True it means that connection to the AP accessPointName was not successful. And this leads to retrying connection to the AP.


def SelectAccessPoint():
    global accessPointName
    accessPointName = u""
    SelectAccessPointIfNoneAvailableAndConnectToIt()


def TelephoneCallBack(state):
    global deviceId

    #NUMBER_WANTED = "786266572"

    myText = "TelephoneCallBack(): Receiving a call from number %s (call state is %s)." % (str(state[1]), str(state[0]))
    if (MY_DEBUG_STDOUT):
        """
        l = len(state[1])
        if (state[1][l - len(NUMBER_WANTED) : l - 1] == NUMBER_WANTED):
            print "Phone number matched ;) ! Retrieving command."
        """
        print myText
        sys.stdout.flush()
    if (MY_DEBUG_UPLOAD_MSG):
        UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)


##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
##################UPLOADING RELATED###########################
NUM_MAX_THREADS_UPLOAD = 20
numThreadsUpload = 1

UPLOAD_USING_UDP = False

#MULTITHREADED_PHOTO_BURST_MODE_UPLOAD = True
MULTITHREADED_PHOTO_BURST_MODE_UPLOAD = False
MULTITHREADED_PHOTO_BURST_MODE_UPLOAD2 = False #True
#MULTITHREADED_PHOTO_BURST_MODE_UPLOAD2 = False
#MULTITHREADED_PHOTO_BURST_MODE_UPLOAD3 = True
MULTITHREADED_PHOTO_BURST_MODE_UPLOAD3 = False

HTTP_INTERNET_UPLOAD_FAST = False #To not call getresponse, use TCP_NODELAY.
#HTTP_INTERNET_UPLOAD_FAST = False




internetUploadErrorsCounter = 0
internetUploadMaxErrors = 100
"""
Note: every function uploading through Internet uses InternetUploadBinaryData().
"""
myHTTPConnection = None
numThreadIssued = 0
def InternetUploadBinaryDataStandard(dataToUpload, inetServerAddress, pageOnServer, itIsASeparateThread = False):
    global myHTTPConnection
    global accessPointName, accessPointNotConnectedTo, bluetoothMode
    global numThreadIssued
    global uploadMediaToiCamServer
    global MY_DEBUG_UPLOAD_MSG

    if (MY_DEBUG_STDOUT):
        print "Entered InternetUploadBinaryData(): time %s, accessPointNotConnectedTo = %d, pageOnServer = %s, len(dataToUpload) = %d, itIsASeparateThread = %d, numThreadIssued = %d." % (GetCurrentDateTimeStringWithMilliseconds(), accessPointNotConnectedTo, pageOnServer, len(dataToUpload), itIsASeparateThread, numThreadIssued)
        sys.stdout.flush()

    if (accessPointNotConnectedTo):
        #We do this to avoid getting the dialog box with the Select AP.
        #Unfortunately, it seems that at least on N95 when the phone's Inet AP doesn't work, trying to reconnect to it doesn't really work...
        SelectAccessPointIfNoneAvailableAndConnectToIt()

    res = 0

    if (NoInternetConnection()): #and bluetoothMode != 2):
        """
        When in offline mode (accessPointName == u"") I save data in Unsent.
        Otherwise, if not uploading, nor storing for later, one can just stop iCam (we assume for the 
        moment iCam is not processing the video info and cannot trigger a notification via SMS/MMS or call).
        """
        if (MY_DEBUG_STDOUT):
            print "InternetUploadBinaryData(): not uploading data now; deferring it for when we have Internet access."
            sys.stdout.flush()
        res = -1
    else:
        #Tell the HTTP command we are sending a gz file and we want text in the response.
        httpRequestHeader = {"Connection:": "Keep-alive", "Content-type": "application/x-gzip", "Accept": "text/plain"}
        #From http://forums.devshed.com/python-programming-11/httplib-urllib-how-do-i-keep-a-connection-open-142565.html: "there is a Connection: Keep-alive option that you can pass in the header, if you use HTTP/1.1 protocol."
        try:
            """
            if (HTTP_INTERNET_UPLOAD_FAST == False):
                myHTTPConnection = httplib.HTTPConnection(inetServerAddress)
            """
            myHTTPConnection = httplib.HTTPConnection(inetServerAddress)

            """
            !!!!len(dataToUpload) might be big (> 1MB), and it is not good to read all data in RAM at once. So do buffered reading and sending.!!!!
            From http://docs.python.org/library/httplib.html.
            HTTPConnection.request(method, url[, body[, headers]])
            This will send a request to the server using the HTTP request method method and the selector url.
            If the body argument is present, it should be a string of data to send after the headers are finished.
            !!!!Alternatively, it may be an open file object, in which case the contents of the file is sent; this file object should support fileno() and read() methods.
            The header Content-Length is automatically set to the correct value.
            The headers argument should be a mapping of extra HTTP headers to send with the request.
            """
            myHTTPConnection.request("POST", pageOnServer, dataToUpload, httpRequestHeader)

            """
            From http://docs.python.org/library/httplib.html:
            "Note that you must have read the whole response before you can send a new request to the server."
            But I am not doing this...
            """

            """
            #Get the response.
            httpResponse = myHTTPConnection.getresponse() #From From http://docs.python.org/library/httplib.html: "Note that you must have read the whole response before you can send a new request to the server."
            """

            if (HTTP_INTERNET_UPLOAD_FAST == False):
                #Get the response.
                httpResponse = myHTTPConnection.getresponse() #From From http://docs.python.org/library/httplib.html: "Note that you must have read the whole response before you can send a new request to the server."

                """
                I don't really believe this info from 2003 is valid now: From http://mail.python.org/pipermail/tutor/2003-May/022635.html: 
                "In order to re-use the connection, before you make the next request, you need to read the data from the last request.  Not sure why that is, but thats the way it is.  So make sure you do your read.  Hope that helps someone else out there."
                """
                httpResponseString = httpResponse.read()
                if (MY_DEBUG_STDOUT):
                    print "InternetUploadBinaryData(): httpResponseString = %s." % httpResponseString
                    sys.stdout.flush()

                #Close the connection.
                myHTTPConnection.close()
            """
            else:
                #Close the connection - I don't like to leave so many connections open... :)
                myHTTPConnection.close()
            """

            #Reset internetUploadErrorsCounter when successful:
            #internetUploadErrorsCounter = 0
        except:
            #!!!!Try myHTTPConnection.close() - maybe otherwise connections get hanged when comm errors take place. 

            #SelectAccessPoint() #!!!!Not really a good idea SelectAccessPoint() - if there is an error from the operator, we don't want to have a dialog appearing asking for selecting an Access Point.
            #global accessPointName
            #accessPointName = u""
            myText = "InternetUploadBinaryData() returned exception. Details: time = %s, free_ram = %d.\n" % (GetCurrentDateTimeStringNice(), GetFreeRAM())
            if (MY_DEBUG_STDOUT):
                #exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
                #repr(traceback.format_tb(exceptionTraceback))
                print myText
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                sys.stderr.write(myText + "\n")
                traceback.print_exc()
                sys.stderr.flush()
            global internetUploadErrorsCounter
            if ((internetUploadErrorsCounter % 10) == 10 - 1):
                if (iOS_PYOBJC):
                    if (MY_DEBUG_STDOUT):
                        print "InternetUploadBinaryData(): internetUploadErrorsCounter became %d and accessPointNotConnectedTo = %d." % (internetUploadErrorsCounter, accessPointNotConnectedTo)
                        sys.stdout.flush()
            internetUploadErrorsCounter += 1
            """
            if (accessPointName == u""): #The user can choose an AP only if he wishes from the Application menu or from the Remote Control Panel
                SelectAccessPointIfNoneAvailableAndConnectToIt()
            """
            res = -1

    #Save data in Unsent.
    #!!!!TODO: Move Save data in Unsent in UploadGZippedData(), in order to have it for BT transmission as well.
    if ((res == -1) and (saveUnsentPackets > 0)):
        if   (pageOnServer == WEBPAGE_UL_GZIPPED_TEXT):
            if (saveUnsentPackets != 2):
                fileExtension = EXTENSION_TEXT_MESSAGE
            else:
                fileExtension = None
        elif ((pageOnServer == WEBPAGE_UL_GZIPPED_STATE_AND_FILE) or (pageOnServer == WEBPAGE_UL_GZIPPED_STATE_AND_FILE_PROXY_YOUTUBE)):
            fileExtension = EXTENSION_STATE_AND_MEDIA_FILE
        elif (pageOnServer == WEBPAGE_UL_GZIPPED_FILE):
            #Currently not implemented.
            fileExtension = EXTENSION_ARBITRARY_FILE
            #return -1

        try:
            if (fileExtension != None):
                """
                crtTime2 = time.time()
                numMilliseconds = (crtTime2 - int(crtTime2)) * 1000 #See http://discussion.forum.nokia.com/forum/showthread.php?116978-What-is-the-time-granularity-in-Pys60 .
                fileName = time.strftime("%Y_%m_%d_%H_%M_%S", crtTime) + ("_%03d%s" % (numMilliseconds, fileExtension))
                """
                fileName = GetCurrentDateTimeStringWithMilliseconds() + fileExtension
                fOutput = open(LOCAL_FOLDER_UNSENT_FILES + "/" + fileName, "wb")
                fOutput.write(dataToUpload)
                #fOutput.flush()
                fOutput.close()
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

    return res


InternetUploadBinaryData = InternetUploadBinaryDataStandard


def AddPacketHeader(rawData):
    global deviceId
    return struct.pack("<100s", deviceId) + rawData #IMPORTANT: We require < to specify no alignment (see http://docs.python.org/library/struct.html)

"""
InternetUploadGZippedData() is used to send media files and text messages.
"""
def InternetUploadGZippedData(aDeviceId, uncompressedData, inetServerAddress, pageOnServer):
    global accessPointName
    global LOCAL_FOLDER_UNSENT_FILES
    global EXTENSION_TEXT_MESSAGE, EXTENSION_STATE_AND_MEDIA_FILE, EXTENSION_ARBITRARY_FILE
    global WEBPAGE_UL_GZIPPED_TEXT, WEBPAGE_UL_GZIPPED_STATE_AND_FILE, WEBPAGE_UL_GZIPPED_FILE

    try:
        if (MY_DEBUG_STDOUT):
            print "Entered InternetUploadGZippedData(%s): accessPointName = %s, pageOnServer = %s, len(uncompressedData) = %d." % (aDeviceId, accessPointName, pageOnServer, len(uncompressedData))
            sys.stdout.flush()

        #Add deviceId identifier in front of uncompressedData.
        #uncompressedData = struct.pack("100s", aDeviceId) + uncompressedData + "\n"
        #uncompressedData = struct.pack("100s", aDeviceId) + uncompressedData
        uncompressedData = AddPacketHeader(uncompressedData)

        #Gzip the data.
        compressedData = uncompressedData.encode("zlib")

        return InternetUploadBinaryData(compressedData, inetServerAddress, pageOnServer)
    except:
        if (MY_DEBUG_STDOUT):
            print "InternetUploadGZippedData exception."
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
        return -1


def UploadBinaryData(dataToUpload, inetServerAddress, inetPageOnServer, fileName = None): #fileName is currently used ONLY for media files.
    global MY_DEBUG_STDOUT, bluetoothMode, accessPointName, bluetoothServerAddress

    PetWatchdog()

    myText = "UploadBinaryData(): len(dataToUpload) = %d (size of data packet sent in bytes), inetServerAddress = %s, inetPageOnServer = %s, fileName = %s." % (len(dataToUpload), inetServerAddress, inetPageOnServer, fileName)

    if (inetPageOnServer == WEBPAGE_UL_GZIPPED_STATE_AND_FILE):
        if (bluetoothMode == 2): #BT client
            #[!CHANGED_FROM_ORIGINAL!]
            pass
        else:
            #It should ALWAYS hold: aDeviceId == deviceId. Impersonating a different phone is no longer necessary - I was using this before, to relay a message.
            #if (not pathFileName.startswith(LOCAL_FOLDER_UNSENT_FILES) and bluetoothMode == 1): #First condition is to avoid calling very often UploadUnsentFILES() and 2nd is to check if it is the BT server.
            if (bluetoothMode == 0 or bluetoothMode == 1): #If the phone is standalone (not BT) or BT server.
                UploadUnsentFILES() #Attempting to send the unsent files, as well, before sending the current data.
            myText += "Uploading via Internet."
            if (MY_DEBUG_STDOUT):
                print myText
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                sys.stderr.write(myText + "\n")
                sys.stderr.flush()
            res = InternetUploadBinaryData(dataToUpload, inetServerAddress, inetPageOnServer)
            if (MY_DEBUG_STDOUT):
                print "UploadBinaryData(): InternetUploadBinaryData returned %d." % (res)
                sys.stdout.flush()
            return res

    elif (inetPageOnServer == WEBPAGE_UL_GZIPPED_TEXT):
        if (bluetoothMode == 2): #BT client
            #[!CHANGED_FROM_ORIGINAL!]
            pass
        else:
            return InternetUploadBinaryData(dataToUpload, inetServerAddress, inetPageOnServer)

    elif (inetPageOnServer == WEBPAGE_UL_GZIPPED_FILE):
        if (bluetoothMode == 2): #BT client
            #[!CHANGED_FROM_ORIGINAL!]
            pass
        else:
            myText += "Uploading via Internet."
            if (MY_DEBUG_STDOUT):
                print myText
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                sys.stderr.write(myText + "\n")
                sys.stderr.flush()
            return InternetUploadBinaryData(dataToUpload, inetServerAddress, inetPageOnServer)


"""
Uploads via Internet or Bluetooth, depending on bluetoothMode.
fileName is required for BluetoothUploadGZippedData - on Bluetooth we specify the type of packet sent via the file name.
The bluetoothServerAddress is global; !!!!inetServerAddress should be made global, then.
"""
def UploadGZippedData(aDeviceId, uncompressedData, inetServerAddress, inetPageOnServer, fileName = None):
    """
    !!!!
    struct.pack()
    UploadBinaryData(aDeviceId, uncompressedData, inetServerAddress, inetPageOnServer, fileName)
    """
    global MY_DEBUG_STDOUT, bluetoothMode, accessPointName, bluetoothServerAddress

    PetWatchdog()

    myText = "UploadGZippedData(): len(uncompressedData) = %d, inetServerAddress = %s, inetPageOnServer = %s, fileName = %s. " % (len(uncompressedData), inetServerAddress, inetPageOnServer, fileName)

    if (inetPageOnServer == WEBPAGE_UL_GZIPPED_STATE_AND_FILE):
        if (bluetoothMode == 2): #BT client
            #[!CHANGED_FROM_ORIGINAL!]
            pass
        else:
            if (accessPointName != u"" and (accessPointNotConnectedTo == False)):
                #It should ALWAYS hold: aDeviceId == deviceId. Impersonating a different phone is no longer necessary - I was using this before, to relay a message.
                #if (not pathFileName.startswith(LOCAL_FOLDER_UNSENT_FILES) and bluetoothMode == 1): #First condition is to avoid calling very often UploadUnsentFILES() and 2nd is to check if it is the BT server.
                if (bluetoothMode == 0 or bluetoothMode == 1): #If the phone is standalone (no BT) or BT server:
                    UploadUnsentFILES() #Attempting to send the unsent media files, as well, before sending the current media file.
            myText += "Uploading via Internet."
            if (MY_DEBUG_STDOUT):
                print myText
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                sys.stderr.write(myText + "\n")
                sys.stderr.flush()
            res = InternetUploadGZippedData(aDeviceId, uncompressedData, inetServerAddress, inetPageOnServer)
            if (MY_DEBUG_STDOUT):
                print "UploadGZippedData(%s): InternetUploadGZippedData returned %d." % (aDeviceId, res)
                sys.stdout.flush()
            return res

    elif (inetPageOnServer == WEBPAGE_UL_GZIPPED_TEXT):
        if (bluetoothMode == 2): #BT client
            #[!CHANGED_FROM_ORIGINAL!]
            pass
        else:
            return InternetUploadGZippedData(aDeviceId, uncompressedData, inetServerAddress, inetPageOnServer)

    elif (inetPageOnServer == WEBPAGE_UL_GZIPPED_FILE):
        if (bluetoothMode == 2): #BT client
            #[!CHANGED_FROM_ORIGINAL!]
            pass
        else:
            myText += "Uploading via Internet."
            if (MY_DEBUG_STDOUT):
                print myText
                sys.stdout.flush()
            if (MY_DEBUG_STDERR_2):
                sys.stderr.write(myText + "\n")
                sys.stderr.flush()
            return InternetUploadGZippedData(aDeviceId, uncompressedData, inetServerAddress, inetPageOnServer)


def GetGPSPosition():
    global readGPS
    global gpsInfo

    if (readGPS):
        if (MY_DEBUG_STDOUT):
            print "Entered GetGPSPosition() - readGPS = %s." % readGPS
            sys.stdout.flush()
        try:
            if (MY_DEBUG_STDOUT):
                print "GPS last_position: ", positioning.last_position()
                print "Reading current GPS coordinates..."
                sys.stdout.flush()
            #                     position(course=0, satellites=0, callback=None, interval=positioning.POSITION INTERVAL, partial=0)
            gpsInfo = positioning.position(1,        1) #from PyS60 doc: Note that the first position()-call may take a long time (because of gps technology).
            if (MY_DEBUG_STDOUT):
                print "GPS position: %s." % gpsInfo
                sys.stdout.flush()
        except:
            if (MY_DEBUG_STDOUT):
                print "GetGPSPosition(): positioning.last_position() or position() returned an exception."
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

        appuifw.note(u"Returned from reading current GPS coordinates...", "info")

        if (isNaN(gpsInfo["course"]["speed"])):
            gpsInfo["course"]["speed"] = -1.0
        if (isNaN(gpsInfo["course"]["heading"])):
            gpsInfo["course"]["heading"] = -1.0
        if (isNaN(gpsInfo["course"]["heading_accuracy"])):
            gpsInfo["course"]["heading_accuracy"] = -1.0
        if (isNaN(gpsInfo["course"]["speed_accuracy"])):
            gpsInfo["course"]["speed_accuracy"] = -1.0
    else:
        gpsInfo["position"]["latitude"] = 0.0
        gpsInfo["position"]["longitude"] = 0.0
        gpsInfo["position"]["altitude"] = 0.0
        gpsInfo["position"]["vertical_accuracy"] = 0.0
        gpsInfo["position"]["horizontal_accuracy"] = 0.0
        gpsInfo["course"]["speed"] = 0.0
        gpsInfo["course"]["heading"] = 0.0
        gpsInfo["course"]["heading_accuracy"] = 0.0
        gpsInfo["course"]["speed_accuracy"] = 0.0
        gpsInfo["satellites"]["horizontal_dop"] = 0.0
        gpsInfo["satellites"]["vertical_dop"] = 0.0
        gpsInfo["satellites"]["time_dop"] = 0.0
        gpsInfo["satellites"]["time"] = 0.0
        gpsInfo["satellites"]["used_satellites"] = -1
        gpsInfo["satellites"]["satellites"] = -1

    """
    if (MY_DEBUG_STDOUT):
        print "Exiting GetGPSPosition()"
        sys.stdout.flush()
    """


def CopyFile(srcPathFileName, dstFileName, myCopyBufferSize = 16 * 1024):
    try:
        srcFile = open(srcPathFileName, "rb")
        dstFile = open(dstFileName, "wb")

        while (True):
            myCopyBuffer = srcFile.read(myCopyBufferSize)
            if (myCopyBuffer):
                dstFile.write(myCopyBuffer)
            else:
                break

        srcFile.close()
        dstFile.close()
    except:
        if (MY_DEBUG_STDERR):
            sys.stderr.write("CopyFile(%s, %s, %d): exception.\n" % (srcPathFileName, dstFileName, myCopyBufferSize))
            traceback.print_exc()
            sys.stderr.flush()
        return -1
    return 0


def MoveFileBetweenAnyDrives(srcPathFileName, dstPathFileName):
    if (srcPathFileName[0 : 2] != dstPathFileName[0 : 2]): #!!!!This assumes running on Symbian or Windows
        #The source and destination drives differ so moving implies copying src to dst and deleting src.
        if (CopyFile(srcPathFileName, dstPathFileName) == -1):
            return -1
        try:
            os.unlink(srcPathFileName)
        except:
            if (MY_DEBUG_STDERR):
                sys.stderr.write("MoveFileBetweenAnyDrives(%s, %s): exception.\n" % (srcPathFileName, dstPathFileName))
                traceback.print_exc()
                sys.stderr.flush()
    else:
        try:
            os.rename(srcPathFileName, dstPathFileName)
        except:
            if (MY_DEBUG_STDERR):
                sys.stderr.write("MoveFileBetweenAnyDrives(%s, %s): exception.\n" % (srcPathFileName, dstPathFileName))
                traceback.print_exc()
                sys.stderr.flush()
            return -1
    return 0


secretKey = "!!!!Write your own secret key123" #A 32 bytes long randomly generated (by hand :) ) secret key
#secretKey = secretKey[:32]
AES_IV = "!!!!16bytestring" #From C:\Python25\Lib\site-packages\gdata\tlslite\utils\cipherfactory.py "param IV: A 16 byte string"

def StoreLocalStateInFile():
    global googleUsername, googlePassword, googleRememberPassword
    global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer, googleKeywords, googleMediaPrivate

    if (MY_DEBUG_STDOUT):
        print "Entered StoreLocalStateInFile()."
        sys.stdout.flush()

    if (gdataModulesImported == False):
        ImportGdataModules()
    """
    if (not gdataModulesImported):
        return
    """

    try:
        fOutput = open(STATE_LOCAL_FILENAME, "w")

        fOutput.write(googleUsername + "\n")

        if (googleRememberPassword):
            """
            Padding spaces at the end of googlePassword since it needs to be multiple of 16 chars long.
                From C:\Python25\Lib\site-packages\gdata\tlslite\utils\AES.py
                    assert(len(plaintext) % 16 == 0)
            """
            plainText = GetGooglePassword()
            while (len(plainText) % 16 != 0):
                plainText += " "
            #cipher = Python_AES.new(secretKey, 2, AES_IV)
            cipher = gdata.tlslite.utils.Python_AES.new(secretKey, 2, AES_IV)
            encodedText = base64.b64encode(cipher.encrypt(plainText)) #clearText
            #print "encoded = %s" % encodedText
            fOutput.write(encodedText + "\n")
        else:
            fOutput.write("\n")

        fOutput.write(str(int(uploadMediaToYouTube)) + "\n")

        fOutput.write(str(int(uploadMediaToPicasa)) + "\n")

        fOutput.write(str(int(uploadMediaToiCamServer)) + "\n")

        fOutput.write(str(int(googleRememberPassword)) + "\n")

        fOutput.write(str(int(googleMediaPrivate)) + "\n")

        fOutput.write(googleKeywords + "\n")

        #fOutput.flush()
        fOutput.close()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


try:
    import base64
except:
    if (MY_DEBUG_STDERR):
        traceback.print_exc()
        sys.stderr.flush()
#Have to declare atom and gdata global in order to import the modules in the global scope in ImportGdataModules().
atom = None
gdata = None

gdataModulesImported = False
def ImportGdataModules():
    global atom, gdata
    global gdataModulesImported

    if (MY_DEBUG_STDOUT):
        print "Entered ImportGdataModules(): gdataModulesImported = %d." % gdataModulesImported
        sys.stdout.flush()

    if (gdataModulesImported == False):
        try:
            if (gdata == None):
                import gdata

            if (uploadMediaToYouTube or uploadMediaToPicasa):
                #if (atom == None):
                import atom
                """
                #As suggested in http://effbot.org/zone/import-confusion.htm, I could give
                atom = __import__("atom")
                #but this doesn't work well for "gdata.youtube" :) - it gives error when loading module gdata.youtube because it is written trickier... :)
                """
                #See maybe http://docs.python.org/release/2.5.2/ref/import.html

                import gdata.media

                if (uploadMediaToYouTube):
                    import gdata.youtube
                    import gdata.youtube.service
                if (uploadMediaToPicasa):
                    import gdata.photos
                    import gdata.photos.service #gives MemoryError if I use default.py the plain text script

            import gdata.tlslite.utils.Python_AES

            gdataModulesImported = True
        except:
            gdataModulesImported = False
            if (MY_DEBUG_STDOUT):
                print "Not able to import the gdata (and atom) modules."
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()
#ImportGdataModules()


#We try to be "lazy" (as in lazy evaluation) in importing the gdata modules - we want to import them ALAP.
def GetGooglePassword():
    global googlePasswordEncrypted, googlePassword

    try:
        if (googlePassword != None):
            return googlePassword

        #googlePasswordEncrypted contains the password read from STATE_LOCAL_FILENAME
        if (googlePasswordEncrypted == None):
            return ""
        else:
            if (gdataModulesImported == False):
                ImportGdataModules()

            #I need to reinitialize the Python_AES for decryption because the self.IV which is initalized with the 3rd param in new() is changed at every Python_AES.encrypt() call, so I need self.IV again with the initial value.
            #cipher = Python_AES.new(secretKey, 2, AES_IV)
            cipher = gdata.tlslite.utils.Python_AES.new(secretKey, 2, AES_IV)
            googlePasswordAux = cipher.decrypt(base64.b64decode(googlePasswordEncrypted))
            #print "decodedText = %s" % decodedText
            """
            if (MY_DEBUG_STDOUT):
                print "LoadStateLocalFromFile(): googlePassword = %s." % googlePassword
                sys.stdout.flush()
            """

            #We remove the added spaces at the end of the password to make it have length % 16 == 0.
            #Funny: if we leave the password with trailing spaces gdata + youtube don't complain and it logs in.
            return googlePasswordAux.rstrip()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


stateLoaded = False
def LoadStateLocalFromFile(pathFileName):
    #global googleUsername, googlePassword, googleRememberPassword, uploadMediaToYouTube, uploadMediaToPicasa, googleKeywords, googleMediaPrivate
    global googleUsername, googlePasswordEncrypted, googleRememberPassword
    global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer, googleMediaPrivate, googleKeywords
    global saveUnsentPackets, internetUploadMaxErrors

    if (MY_DEBUG_STDOUT):
        print "Entered LoadStateLocalFromFile()"
        sys.stdout.flush()

    """
    if (not gdataModulesImported):
        return
    """
    def ReadNextNonCommentLine(fInput, rstripStr = None):
        try:
            while True:
                fLine = fInput.readline()
                if (fLine):
                    fLine = fLine.rstrip(rstripStr)
                else:
                    return None
                if (not fLine.startswith("//INFO:")):
                    return fLine
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

    try:
        if (os.path.isfile(pathFileName)):
            fInput = open(pathFileName, "r")

            fLine = ReadNextNonCommentLine(fInput)
            if (fLine == None):
                return
            googleUsername = fLine.rstrip()

            fLine = ReadNextNonCommentLine(fInput, "\r\n")
            if (fLine == None):
                return
            googlePasswordEncrypted = fLine

            fLine = ReadNextNonCommentLine(fInput)
            if (fLine == None):
                return
            uploadMediaToYouTube = fLine
            uploadMediaToYouTube = int(uploadMediaToYouTube)

            fLine = ReadNextNonCommentLine(fInput)
            if (fLine == None):
                return
            uploadMediaToPicasa = fLine
            uploadMediaToPicasa = int(uploadMediaToPicasa)

            fLine = ReadNextNonCommentLine(fInput)
            if (fLine == None):
                return
            uploadMediaToiCamServer = fLine
            uploadMediaToiCamServer = int(uploadMediaToiCamServer)

            fLine = ReadNextNonCommentLine(fInput)
            if (fLine == None):
                return
            googleRememberPassword = fLine
            googleRememberPassword = int(googleRememberPassword)

            fLine = ReadNextNonCommentLine(fInput)
            if (fLine == None):
                return
            googleMediaPrivate = fLine
            googleMediaPrivate = int(googleMediaPrivate)

            fLine = ReadNextNonCommentLine(fInput)
            if (fLine == None):
                return
            googleKeywords = fLine

            #fInput.flush()
            fInput.close()
        else:
            if (MY_DEBUG_STDOUT):
                print "LoadStateLocalFromFile(): could not find file %s." % pathFileName
                sys.stdout.flush()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

    if (MY_DEBUG_STDOUT):
        try:
            print "LoadStateLocalFromFile(): read the following:"
            print "    googleUsername =", googleUsername
            #print "    googlePassword =", googlePassword
            print "    googleRememberPassword =", googleRememberPassword
            print "    uploadMediaToYouTube =", uploadMediaToYouTube
            print "    uploadMediaToPicasa =", uploadMediaToPicasa
            print "    uploadMediaToiCamServer =", uploadMediaToiCamServer
            print "    googleMediaPrivate =", googleMediaPrivate
            print "    googleKeywords =", googleKeywords
            sys.stdout.flush()
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()


#[!CHANGED_FROM_ORIGINAL!]: Took out comments
statePackFormat00 = "<i"
statePackFormat01 = "<bbbbiiiiibbbbbbbb"
statePackFormat02 = "<50s20si"
statePackFormat03 = "<iiiiiii"
statePackFormat04 = "<iqqiii"
statePackFormat05 = "<2si"
statePackFormat06 = "<iiiiiiii"
statePackFormat07 = "<iiiiiii"
statePackFormat08 = "<iiii"
statePackFormat09 = "<32s32s32s32s"
statePackFormat10 = "<iiiibbbb" 
statePackFormat11 = "<20s"
statePackFormat12 = "<i24s"
statePackFormat13 = "<i28s"
statePackFormat14 = "<iiii"
statePackFormat15 = "<32s"
statePackFormat16 = "<i28s"
statePackFormat17 = "<if24s"
statePackFormat18 = "<32s32s32s32s"
statePackFormat19 = "<32s"
statePackFormat20 = "<dddddddddddddii"
statePackFormat21 = "<32s32s"
statePackFormat22 = "<i28s"
statePackFormat23 = "<32s32s32s32s32s32s32s32s32s32s32s32s32s"
statePackFormat24 = "<20sbbbbbbbb"
statePackFormat25 = "<i128s128s"

statePackFormat  = statePackFormat00       + statePackFormat01[1 : ] + statePackFormat02[1 : ] + statePackFormat03[1 : ] + statePackFormat04[1 : ]
statePackFormat += statePackFormat05[1 : ] + statePackFormat06[1 : ] + statePackFormat07[1 : ] + statePackFormat08[1 : ] + statePackFormat09[1 : ]
statePackFormat += statePackFormat10[1 : ] + statePackFormat11[1 : ] + statePackFormat12[1 : ] + statePackFormat13[1 : ] + statePackFormat14[1 : ]
statePackFormat += statePackFormat15[1 : ] + statePackFormat16[1 : ] + statePackFormat17[1 : ] + statePackFormat18[1 : ] + statePackFormat19[1 : ]
statePackFormat += statePackFormat20[1 : ] + statePackFormat21[1 : ] + statePackFormat22[1 : ] + statePackFormat23[1 : ] + statePackFormat24[1 : ]
statePackFormat += statePackFormat25[1 : ]
def LoadStateFromFile(pathFileName):
    #[!CHANGED_FROM_ORIGINAL!]
    pass


if (iOS_PYOBJC):
    PETTING_FILENAME = LOCAL_FOLDER + "/iCamAlive"
def PetWatchdog():
    #Another idea: check modif time of STATE_FILENAME if always updating it in UploadStateAndFileAndStoreState() - this actually happens only for fileName == None
    #maybe save file in LOCAL_FOLDER.

    if (MY_DEBUG_STDOUT):
        print "Entered PetWatchdog() at %s." % GetCurrentDateTimeStringNice()
        sys.stdout.flush()

    try:
        #if (not os.path.exists(PETTING_FILENAME)):
        if (not os.path.isfile(PETTING_FILENAME)):
            fOutput = open(PETTING_FILENAME, "wb") 
            #fOutput.write()
            fOutput.close()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


try:
    import pyiqe
    hasPyIQE = True
except:
    hasPyIQE = False
    if (MY_DEBUG_STDERR):
        traceback.print_exc()
        sys.stderr.flush()
IQE_KEY = "!!!!Write your own key"
IQE_SECRET = "!!!!Write your own"
def IQEnginesPhotoUpload(photoPathFileName):
    if (hasPyIQE == False):
        return

    try:
        #From readme.md
        iqe = pyiqe.Api(IQE_KEY, IQE_SECRET)

        #Alex commented this
        #iqe = Api(version="1.2")

        if (MY_DEBUG_STDOUT):
            print "IQEnginesPhotoUpload(): Time before query: %s." % GetCurrentDateTimeStringWithMilliseconds()
            sys.stdout.flush()

        response, qid = iqe.query(photoPathFileName) #"C:/OpenCV2.2/samples/python/1Good/snap00027_bla.bmp"
        
        if (MY_DEBUG_STDOUT):
            print "IQEnginesPhotoUpload(): Time after query: %s. response = %s." % (GetCurrentDateTimeStringWithMilliseconds(), str(response))
            sys.stdout.flush()

        """
        From http://developer.iqengines.com/apidoc/current/faqs/index.html#what-is-the-crowdsourcing-api
        Can you recognize multiple objects?
        Yes! We return by default the strongest match only. If you would like to retrieve all objects that are identified in your images, you can pass the multiple_results paramter in your Query API request.
        """

        if (MY_DEBUG_STDOUT):
            print "IQEnginesPhotoUpload(): sending in query with qid %s." % qid
            sys.stdout.flush()

        #assert response == {'data': {'error': 0}}, "Invalid Response while querying: \n%s " % response
        if (response != {u"data": {"error": 0}}):
            return
        
        if (MY_DEBUG_STDOUT):
            print "\nIQEnginesPhotoUpload(): waiting for results..."
            sys.stdout.flush()

        response = iqe.update()

        if (MY_DEBUG_STDOUT):
            print(response)
            sys.stdout.flush()

        if (MY_DEBUG_STDOUT):
            print "IQEnginesPhotoUpload(): Time after update(): %s." % GetCurrentDateTimeStringWithMilliseconds()
            sys.stdout.flush()
        
        if (MY_DEBUG_STDOUT):
            print "\nIQEnginesPhotoUpload(): retrieving results manually."
            sys.stdout.flush()

        #time.sleep(2)
        #time.sleep(20)
        #time.sleep(60)
        SleepAndPetWatchdog(60.0)

        response = iqe.result(qid)

        if (MY_DEBUG_STDOUT):
            print "IQEnginesPhotoUpload(): response = %s." % (str(response))
            sys.stdout.flush()

        """
        Possible responses: 
            {u'data': {u'results': [{u'color': u'Mostly gray brown, with some blue.', u'labels': u'Titan'}], u'error': 0}}.
            {u'data': {u'comment': u'The results for qid 82e6b37dfcd16b273cd861e21c74f8c0d7a0ba6c are not available yet', u'error': 0}}.
        """
        if ( int(response[u"data"][u"error"]) != 0 ):
            return

        #responseToDisplay = str(response[u"data"][u"results"][0][u"labels"])
        responseToDisplay = ""
        for key in response[u"data"]:
            if (key != "error"):
                #print response[u"data"][key]
                responseToDisplay += str(response[u"data"][key])

        if (MY_DEBUG_STDOUT):
            #print "IQEnginesPhotoUpload(): response = %s. responseToDisplay = %s." % (str(response), responseToDisplay)
            print "IQEnginesPhotoUpload(): responseToDisplay = %s." % (responseToDisplay)
            sys.stdout.flush()
        DisplayNote("IQE tagged photo as %s." % responseToDisplay, -1.0)

        if (MY_DEBUG_STDOUT):
            print "IQEnginesPhotoUpload(): Time after result(): %s" % GetCurrentDateTimeStringWithMilliseconds()
            sys.stdout.flush()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


YOUTUBE_TEST_CLIENT_ID = "ytapi-pythonclientlibrary_servicetest"
youtubeDeveloperKey = "!!!!Write your own YouTube developer key here"
#!!!!Allow to change them through the iCam UI - maybe save them in state.
"""
googleUsername = "MOBILEREVIVAL"
googleKeywords = "Cernica"
"""
googleUsername = None
googlePassword = None
googlePasswordEncrypted = None
googleKeywords = deviceId

uploadMediaToYouTube = 0
uploadMediaToPicasa = 0
uploadMediaToiCamServer = 0 #This should be 0
uploadMediaToIQEngines = 0
googleRememberPassword = 1
googleMediaPrivate = 1

youtubeClient = None
youtubeClientAlreadyConnected = False
def ConnectToYouTubeGData():
    global youtubeClient, youtubeClientAlreadyConnected

    if (MY_DEBUG_STDOUT):
        print "Entered ConnectToYouTubeGData()."
        sys.stdout.flush()

    try:
        youtubeClient = gdata.youtube.service.YouTubeService()
        youtubeClient.email = googleUsername
        #youtubeClient.email = "sgs637"

        youtubeClient.password = GetGooglePassword()
        #youtubeClient.password = ""

        youtubeClient.source = YOUTUBE_TEST_CLIENT_ID
        youtubeClient.developer_key = youtubeDeveloperKey
        youtubeClient.client_id = YOUTUBE_TEST_CLIENT_ID
        youtubeClient.ProgrammaticLogin()
        youtubeClientAlreadyConnected = True
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        errorStr = "Exception in ConnectToYouTubeGData() - details: free_ram = %d. exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s. Bailing out..." % ( GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, errorStr, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

        if (MY_DEBUG_STDOUT):
            print errorStr
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

        if (exceptionValue == "The connect operation timed out"):
        #str(exceptionType).find("socket.sslerror") #<class 'socket.sslerror'>
            Quit()

        return -1


def YouTubeVideoUpload(pathFileName, fileName, aKeyword, crtTime = None, mediaTimeStr = "", mediaDateStr = "", deviceId = "", cameraId = 0):
    """
    Note:
    The fileName is the time when was given start recording (note that at least on Symbian there might be a small delay before actually starting to record).
    The (YouTube) videoDescription represents the time we entered UploadStateAndFileAndStoreState().
    """
    global youtubeClient, youtubeClientAlreadyConnected
    global YOUTUBE_TEST_CLIENT_ID, googleUsername, youtubeDeveloperKey

    if (MY_DEBUG_STDOUT):
        print "Entered YouTubeVideoUpload(pathFileName = %s, fileName = %s, aKeyword = %s)." % (pathFileName, fileName, aKeyword)
        sys.stdout.flush()

    pass


picasaClient = None
picasaClientAlreadyConnected = False
def ConnectToPicasaGData():
    global picasaClient, picasaClientAlreadyConnected

    if (MY_DEBUG_STDOUT):
        print "Entered ConnectToPicasaGData()."
        sys.stdout.flush()

    try:
        # Initialize the client
        picasaClient = gdata.photos.service.PhotosService()
        picasaClient.email = googleUsername
        picasaClient.password = GetGooglePassword()
        picasaClient.source = "iCam Client"
        picasaClient.ProgrammaticLogin()
        picasaClientAlreadyConnected = True
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        errorStr = "Exception in ConnectToPicasaGData() - details: free_ram = %d. exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s. Bailing out..." % ( GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, errorStr, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

        if (MY_DEBUG_STDOUT):
            print errorStr
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

        if (exceptionValue == "The connect operation timed out"):
            Quit()

        return -1


def PicasaPhotoUpload(pathFileName, fileName, aKeyword, crtTime = None, mediaTimeStr = "", mediaDateStr = "", deviceId = "", cameraId = 0):
    global picasaClient, picasaClientAlreadyConnected

    if (MY_DEBUG_STDOUT):
        print "Entered PicasaPhotoUpload(pathFileName = %s, fileName = %s, aKeyword = %s)." % (pathFileName, fileName, aKeyword)
        sys.stdout.flush()

    if (picasaClientAlreadyConnected == False):
        if (gdataModulesImported == False):
            ImportGdataModules()
        ConnectToPicasaGData()

    try:
        if (crtTime == None):
            albumTitle = deviceId + ": " + mediaDateStr + (", %d" % cameraId)
        else:
            albumTitle = deviceId + ": " + time.strftime("%Y-%m-%d", crtTime) + (", %d" % cameraId)

        iCamAlbumFound = False

        #From https://code.google.com/apis/picasaweb/docs/1.0/developers_guide_python.html#ListAlbums (less important: https://code.google.com/apis/picasaweb/docs/2.0/developers_guide_protocol.html#ListAlbums)
        #albumsFeed = picasaClient.GetUserFeed(kind = "album", user = "ender123")
        albumsFeed = picasaClient.GetUserFeed(kind = "album")
        for album in albumsFeed.entry:
            if (MY_DEBUG_STDOUT):
                #print "album =", album
                print "Title: %s, number of photos: %s, id: %s" % (album.title.text, album.numphotos.text, album.gphoto_id.text)
                sys.stdout.flush()
            #picasaClient.Delete(album)

            if (album.title.text == albumTitle):
                iCamAlbumFound = True
                break

        if (iCamAlbumFound):
            #print "Found"
            iCamAlbum = album
        else:
            iCamAlbum = picasaClient.InsertAlbum(title = albumTitle, summary = "iCam photo album.", location = "Bucharest", access = "private")

        photoEntry = gdata.photos.PhotoEntry()
        
        photoEntry.title = atom.Title(text = fileName)

        photoEntry.private = gdata.media.Private()

        photoEntry.summary = atom.Summary(text = fileName) #"Just a test.")
        photoEntry.category.append(atom.Category(
            scheme = "http://schemas.google.com/g/2005#kind", 
            term = "http://schemas.google.com/photos/2007#photo"))

        photoFileNameExtension = str.lower(pathFileName[len(pathFileName) - 4 : ])
        if (photoFileNameExtension == ".jpg"):
            entry = picasaClient.InsertPhoto(iCamAlbum, photoEntry, pathFileName, content_type = "image/jpeg")
        elif (photoFileNameExtension == ".png"):
            entry = picasaClient.InsertPhoto(iCamAlbum, photoEntry, pathFileName, content_type = "image/png")
    except:
        #In case there was an error when uploading to YouTube, then save the media file to the Unsent folder.
        if ((storeLocallyMedia == 0) and (not uploadMediaToiCamServer)): #storeLocallyMedia == 0 because in case we don't store it THEN we save it in Unsent
            if (saveUnsentPackets > 0):
                MoveFileBetweenAnyDrives(pathFileName, LOCAL_FOLDER_UNSENT_FILES + "/" + fileName) #Note: we could save this file in LOCAL_FOLDER_MEDIA, but in Unsent is more appropriate.

        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        errorStr = "Exception in PicasaPhotoUpload() - details: free_ram = %d. exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s. Bailing out..." % ( GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, errorStr, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

        if (MY_DEBUG_STDOUT):
            print errorStr
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

        if (exceptionValue == (403, "Forbidden", "Token expired")):
            Quit()
        return -1


def GetYouTubeUserProfile():
    global googleUsername

    userEntry = youtubeClient.GetYouTubeUserEntry("https://gdata.youtube.com/feeds/users/" + googleUsername)
    if (MY_DEBUG_STDOUT):
        #print errorStr
        print "GetYouTubeUserProfile(): userEntry.description.text = %s" % str(userEntry.description.text)
        sys.stdout.flush()
    return userEntry.description.text


googleRes = None #We declare it here, just before the function it uses it, because we use it also in an inner function
NO_MEDIA_FILE_NAME = "[!NO_FILE]"
def UploadStateAndFileAndStoreState(aDeviceId, fileName, pathFileName, cameraId, inetServerAddress, pageOnServer, singleThreaded = False):
    global accessPointName, bluetoothMode, bluetoothServerAddress
    global signalUnits, signalStrength, pauseInterval, burstModeIsStarted, photoResolutionIndex, localPhotoResolutionIndex
    global photoModeIndex, digitalZoom, photoQuality, exposureIndex, whiteBalanceIndex, flashIndex
    global audioRecordDuration, videoRecordDuration
    global localVideoModeIndex, cameraMode, videoAudioEnabled
    global rotateDegreesImage, mobileCountryCode, mobileNetworkCode, locationAreaCode, cellId, gpsInfo
    global statePackFormat, storeLocallyMedia
    global differentPixelsPercentageThreshold
    global modeManagerIsEnabled, dawnTimeVec, duskTimeVec
    global uploadHowManyOfLatestBluetoothMessages, uploadUnsentData, saveUnsentPackets
    global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer
    global internetUploadMaxErrors
    global startAutomatically
    global BATTERY_LEVEL_THRESHOLD
    global MY_DEBUG_STDOUT, MY_DEBUG_STDERR, MY_DEBUG_STDERR_2, MY_DEBUG_UPLOAD_MSG
    global googleRes
    global startViewfinderBeforeTakingPhoto

    if (MY_DEBUG_STDOUT):
        print "Entered UploadStateAndFileAndStoreState() at %s." % (GetCurrentDateTimeStringWithMilliseconds())
        sys.stdout.flush()

    crtTime = GetCurrentDateTime()
    crtTime2 = time.time()
    numMilliseconds = (crtTime2 - int(crtTime2)) * 1000 #See http://discussion.forum.nokia.com/forum/showthread.php?116978-What-is-the-time-granularity-in-Pys60 .

    #PetWatchdog()

    GetGPSPosition()

    mediaFileSize = -1
    if (fileName == None):
        fileNameStr = ""
    else:
        fileNameStr = fileName
        try:
            mediaFileSize = os.path.getsize(pathFileName)
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

    if   (bluetoothMode == 0):
        tmpBluetoothServerAddress = "no_BT"
    elif (bluetoothMode == 1):
        tmpBluetoothServerAddress = "BTServer"
    else:
        tmpBluetoothServerAddress = bluetoothServerAddress

    #[!CHANGED_FROM_ORIGINAL!]
    stateMarshalled  = struct.pack(statePackFormat00, struct.calcsize(statePackFormat))
    myLen = struct.calcsize(statePackFormat) - struct.calcsize(statePackFormat00)
    for i in range(myLen):
        stateMarshalled += "0"

    if (fileName == None):
        try:
            #if os.path.exists(STATE_FILENAME_BACKUP):
            if os.path.isfile(STATE_FILENAME_BACKUP):
                os.unlink(STATE_FILENAME_BACKUP)
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

        try:
            #if os.path.exists(STATE_FILENAME):
            if os.path.isfile(STATE_FILENAME):
                os.rename(STATE_FILENAME, STATE_FILENAME_BACKUP)
            if (MY_DEBUG_STDOUT):
                print "UploadStateAndFileAndStoreState(): renamed %s to %s." % (STATE_FILENAME, STATE_FILENAME_BACKUP)
                sys.stdout.flush()
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

        try:
            fOutput = open(STATE_FILENAME, "wb")
            #fOutput.write(stateMarshalled)
            fOutput.write(stateMarshalled.encode("zlib"))
            #fOutput.flush()
            fOutput.close()
            if (MY_DEBUG_STDOUT):
                print "UploadStateAndFileAndStoreState(): Wrote state in file %s." % STATE_FILENAME
                sys.stdout.flush()
        except:
            exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
            errorStr = "Exception in UploadStateAndFileAndStoreState() when writing locally stateMarshalled to %s - details: free_ram = %d. exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s. Bailing out..." % ( STATE_FILENAME, GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )
            if (MY_DEBUG_UPLOAD_MSG):
                UploadGZippedData(aDeviceId, errorStr, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

            if (MY_DEBUG_STDOUT):
                print errorStr
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()
            return -1

    #stateMarshalled = "%d %d %d %d %d %d ", GetBatteryLevelPercentage(), pauseInterval, burstModeIsStarted, photoResolutionIndex, digitalZoom, photoQuality

    if (fileName == None):
        return 0

    googleRes = 0
    if (str.lower(fileName[len(fileName) - 4 : ]) in [".3gp", ".mp4"]):
        #if (serversUsed == 4):
        if (uploadMediaToYouTube):
            #!!!!We read twice the file pathFileName (actually, do we read it twice?). Can we do better?!!!!
            def MyFuncYouTubeVideoUpload():
                global googleRes
                #googleRes = YouTubeVideoUpload(pathFileName, fileName, googleKeywords, crtTime, None, None, deviceId, cameraId)
                googleRes = YouTubeVideoUpload(pathFileName, fileName, googleKeywords, crtTime, str(int(numMilliseconds)), None, deviceId, cameraId)
                if (singleThreaded == False):
                    #if (SYMBIAN_OS and (pyS60VersionNumber > 14)):
                        #mediaUploadedLock.signal()
                    pass

            if (singleThreaded == True):
                MyFuncYouTubeVideoUpload()
            else:
                #if (storeLocallyMedia == 0):
                #    MyFuncYouTubeVideoUpload()
                MyThreadStart(MyFuncYouTubeVideoUpload)

            #mediaFileData = ""
    elif (str.lower(fileName[len(fileName) - 4 : ]) in [".jpg", ".png", ".bmp"]):
        #if (serversUsed == 4):
        if (uploadMediaToPicasa):
            def MyFuncPicasaPhotoUpload():
                #PicasaPhotoUpload(albumTitle, pathFileName, fileName)
                #PicasaPhotoUpload(pathFileName, fileName, crtTime)
                #googleRes = PicasaPhotoUpload(pathFileName, fileName, googleKeywords, crtTime, None, None, deviceId, cameraId)
                googleRes = PicasaPhotoUpload(pathFileName, fileName, googleKeywords, crtTime, str(int(numMilliseconds)), None, deviceId, cameraId)
                if (singleThreaded == False):
                    #if (SYMBIAN_OS and (pyS60VersionNumber > 14)):
                    #    mediaUploadedLock.signal()
                    pass

            if (singleThreaded == True):
                MyFuncPicasaPhotoUpload()
            else:
                #if (storeLocallyMedia == 0):
                #    MyFuncPicasaPhotoUpload()
                MyThreadStart(MyFuncPicasaPhotoUpload)

            #mediaFileData = ""
    if (googleRes == -1):
        pass

    mediaFileData = ""
    #if (serversUsed != 4):
    if (uploadMediaToiCamServer):
        if (fileName == NO_MEDIA_FILE_NAME):
            #mediaFileData = ""
            pass
        else:
            #!!!!think better
            if (uploadMediaToYouTube and str.lower(fileName[len(fileName) - 4 : ]) in [".3gp", ".mp4"]):
                pass
            else:
                # Read the binary file from disk
                try:
                    fInput = open(pathFileName, "rb")
                    mediaFileData = fInput.read()
                    fInput.close()
                except:
                    exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
                    errorStr = "Exception in UploadStateAndFileAndStoreState() at %s with pathFileName = %s - details: free_ram = %d. exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s. Bailing out..." % ( GetCurrentDateTimeStringNice(), pathFileName, GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )
                    if (MY_DEBUG_UPLOAD_MSG):
                        UploadGZippedData(aDeviceId, errorStr, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

                    if (MY_DEBUG_STDOUT):
                        print "Exception in UploadStateAndFileAndStoreState() at %s with pathFileName = %s. Bailing out..." % (GetCurrentDateTimeStringNice(), pathFileName)
                        sys.stdout.flush()
                    if (MY_DEBUG_STDERR):
                        traceback.print_exc()
                        sys.stderr.flush()
                    return -1

                if ERASE_ORIGINAL_MEDIA_FILE_AFTER_READ:
                    try:
                        os.unlink(pathFileName)
                        #os.remove()
                    except:
                        if (MY_DEBUG_STDERR):
                            traceback.print_exc()
                            sys.stderr.flush()

    #UploadText("The JPEG has %d bytes." % len(data), PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT)

    #data = message + STRING_SEPARATOR + filename + STRING_SEPARATOR + data
    uploadData = stateMarshalled + mediaFileData

    #UploadText("The compressed JPEG has %d bytes." % len(data), PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT)

    if (MY_DEBUG_STDOUT):
        print "UploadStateAndFileAndStoreState(): Sending data of size %d (accessPointName = %s, bluetoothMode = %d)." % (len(uploadData), accessPointName, bluetoothMode)
        sys.stdout.flush()
    #return UploadGZippedData(data, ......, inetServerAddress, pageOnServer)

    #if (inetServerAddress == None):
    myText = "UploadStateAndFileAndStoreState() - details: aDeviceId = %s, fileName = %s, pathFileName = %s, cameraId = %d, time = %s, free_ram = %d." % (aDeviceId, fileName, pathFileName, cameraId, GetCurrentDateTimeStringNice(), GetFreeRAM())
    if (MY_DEBUG_STDOUT):
        print myText
        sys.stdout.flush()
    if (MY_DEBUG_STDERR_2):
        sys.stderr.write(myText + "\n")
        sys.stderr.flush()
    res = UploadGZippedData(aDeviceId, uploadData, inetServerAddress, pageOnServer, fileName)
    if (res == -1):
        pass
    return res


#Used by BluetoothMessageProcess(btMsgId) --> WE MUST NOT CHECK FOR uploadUnsentData HERE, BUT IN THE caller of this function.
def UploadUnsentBinaryData(aDeviceId, fileName, fileData):
    global deviceId

    try:
        PetWatchdog()

        myText = "UploadUnsentBinaryData(aDeviceId = %s, fileName = %s): at %s, calling InternetUploadBinaryData() with data of size %d." % (aDeviceId, fileName, GetCurrentDateTimeStringNice(), len(fileData))
        if (MY_DEBUG_STDOUT):
            print myText
            sys.stdout.flush()
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

        if (fileName[len(fileName) - len(EXTENSION_TEXT_MESSAGE) :] == EXTENSION_TEXT_MESSAGE):
            serverPageToConnectTo = WEBPAGE_UL_GZIPPED_TEXT
        elif (fileName[len(fileName) - len(EXTENSION_STATE_AND_MEDIA_FILE) :] == EXTENSION_STATE_AND_MEDIA_FILE):
            serverPageToConnectTo = WEBPAGE_UL_GZIPPED_STATE_AND_FILE
        elif (fileName[len(fileName) - len(EXTENSION_ARBITRARY_FILE) :] == EXTENSION_ARBITRARY_FILE):
            serverPageToConnectTo = WEBPAGE_UL_GZIPPED_FILE

        res = InternetUploadBinaryData(fileData, PHP_SERVER_NAME, serverPageToConnectTo)
        #UploadStateAndFileAndStoreState(aDeviceId, fileName, pathFileName, cameraId, aYear, aMonth, aDay, aHour, aMinute, aSecond, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE)
        #!!!!I should store also another file?? with the state of the media file from the BT client: cameraId, aYear, aMonth, aDay, aHour, aMinute, aSecond, GPS, etc
        if (res == -1):
            if (MY_DEBUG_STDOUT):
                print "UploadUnsentBinaryData(%s): unsuccessful InternetUploadBinaryData(). Returning..." % (aDeviceId)
                sys.stdout.flush()
            return
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def UploadUnsentFile(aDeviceId, pathFileName):
    global deviceId

    try:
        PetWatchdog()

        myText = "UploadUnsentFile(%s): at %s, calling InternetUploadBinaryData() with data from file %s of size %d bytes." % (aDeviceId, GetCurrentDateTimeStringWithMilliseconds(), pathFileName, os.path.getsize(pathFileName))
        if (MY_DEBUG_STDOUT):
            print myText
            sys.stdout.flush()
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

        if (pathFileName[len(pathFileName) - len(EXTENSION_TEXT_MESSAGE) :] == EXTENSION_TEXT_MESSAGE):
            serverPageToConnectTo = WEBPAGE_UL_GZIPPED_TEXT
        elif (pathFileName[len(pathFileName) - len(EXTENSION_STATE_AND_MEDIA_FILE) :] == EXTENSION_STATE_AND_MEDIA_FILE):
            serverPageToConnectTo = WEBPAGE_UL_GZIPPED_STATE_AND_FILE
        elif (pathFileName[len(pathFileName) - len(EXTENSION_ARBITRARY_FILE) :] == EXTENSION_ARBITRARY_FILE):
            serverPageToConnectTo = WEBPAGE_UL_GZIPPED_FILE

        fInput = open(pathFileName, "rb")
        fileData = fInput.read()
        fInput.close()

        """
        #To experiment burst of packets you can do a forever loop and send one unsent packet
        while (True):
        """
        res = InternetUploadBinaryData(fileData, PHP_SERVER_NAME, serverPageToConnectTo)
        #UploadStateAndFileAndStoreState(aDeviceId, fileName, pathFileName, cameraId, aYear, aMonth, aDay, aHour, aMinute, aSecond, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE)
        #!!!!I should store also another file?? with the state of the media file from the BT client: cameraId, aYear, aMonth, aDay, aHour, aMinute, aSecond, GPS, etc
        if (res == -1):
            if (MY_DEBUG_STDOUT):
                #print "UploadUnsentFile(%s): unsuccessful InternetUploadBinaryData(). Returning..." % (aDeviceId)
                print "UploadUnsentFile(%s): unsuccessful InternetUploadBinaryData(). InternetUploadBinaryData() saved to transmit later the data." % (aDeviceId)
                sys.stdout.flush()
            #return

        if (aDeviceId == deviceId):
            if (MY_DEBUG_STDOUT):
                print "UploadUnsentFile(%s): After successful InternetUploadBinaryData(), deleting temporary media file %s." % (aDeviceId, pathFileName)
                sys.stdout.flush()
            os.unlink(pathFileName)
        else:
            if (MY_DEBUG_STDOUT):
                print "UploadUnsentFile(%s) - relayed data: After successful InternetUploadBinaryData(), deleting .sfm file %s - remember that we have the corresponding media file already saved in the Media folder." % (aDeviceId, pathFileName)
                sys.stdout.flush()
            os.unlink(pathFileName)
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def DoNotUploadUnsent():
    global deviceId, conserveEnergy, uploadUnsentData

    return (uploadUnsentData != 1 and uploadUnsentData != 3) or conserveEnergy or (deviceId == "358064016080560")


def UploadUnsentFolder(aDeviceId, pathFolderName):
    try:
        if (MY_DEBUG_STDOUT):
            print "UploadUnsentFolder(%s): pathFolderName = %s." % (aDeviceId, pathFolderName)
            sys.stdout.flush()

        folderContent = os.listdir(pathFolderName)
        #sortedFolderContent = sorted(folderContent, reverse = False) #Use reverse = False to send first the oldest ones (like this you send in chronological order). Use reverse = True for sending first the most recent ones.
        folderContent.sort() #sort() without parameters is the ONLY one that works in Python 2.2. (Info on sort at http://wiki.python.org/moin/HowTo/Sorting/.)
        sortedFolderContent = folderContent

        counterUnsentPackets = 0
        for fileName in sortedFolderContent:
            #if (True):
            if (fileName[len(fileName) - len(EXTENSION_STATE_AND_MEDIA_FILE) : ] == EXTENSION_STATE_AND_MEDIA_FILE or fileName[len(fileName) - len(EXTENSION_ARBITRARY_FILE) : ] == EXTENSION_ARBITRARY_FILE): #or if (fileName[len(fileName) - len(EXTENSION_TEXT_MESSAGE) :] == EXTENSION_TEXT_MESSAGE):
                if (DoNotUploadUnsent()): #!!!!Maybe take it out, since we check DoNotUploadUnsent() also in UploadUnsentFILES().
                    if (MY_DEBUG_STDOUT):
                        print "UploadUnsentFolder(): exiting UploadUnsentFolder() because conserveEnergy = %d or uploadUnsentData = %d or deviceId = %s." % (conserveEnergy, uploadUnsentData, deviceId)
                        sys.stdout.flush()
                    return

                pathFileName = pathFolderName + "/" + fileName
                if os.path.isdir(pathFileName): #This should happen only when processing the Unsent folder itself.
                    pass
                else:
                    UploadUnsentFile(aDeviceId, pathFileName)
                if ((counterUnsentPackets % NUM_UNSENT_PACKETS_BEFORE_DOWNLOAD_COMMANDS) == NUM_UNSENT_PACKETS_BEFORE_DOWNLOAD_COMMANDS - 1):
                    hasDownloadedNewCmd = DownloadCommands()
                counterUnsentPackets += 1
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def UploadUnsentFILES():
    global deviceId, conserveEnergy, uploadUnsentData

    if (NoInternetConnection()):
        if (MY_DEBUG_STDOUT):
            print "UploadUnsentFILES(): NOT entering UploadUnsentFILES() because accessPointName = %s and accessPointNotConnectedTo = %d." % (accessPointName, accessPointNotConnectedTo)
            sys.stdout.flush()
        return

    if (DoNotUploadUnsent()):
        if (MY_DEBUG_STDOUT):
            print "UploadUnsentFILES(): NOT entering UploadUnsentFILES() because conserveEnergy = %d or uploadUnsentData = %d or deviceId = %s." % (conserveEnergy, uploadUnsentData, deviceId)
            sys.stdout.flush()
        return
    else:
        if (MY_DEBUG_STDOUT):
            print "UploadUnsentFILES(): Entering UploadUnsentFILES()."
            sys.stdout.flush()
        #UploadUnsentFILES() #Attempting to send the unsent media files, as well, before sending the current media file.

    UploadUnsentFolder(deviceId, LOCAL_FOLDER_UNSENT_FILES)

    #!!!Do this only if the phone is BT server.
    #Process also the subfolders of Unsent, which are for the BT clients.
    try:
        folderContent = os.listdir(LOCAL_FOLDER_UNSENT_FILES)

        for folderName in folderContent:
            #if os.path.isdir(folderContent[i]):
            folderPathName = LOCAL_FOLDER_UNSENT_FILES + "/" + folderName

            if (MY_DEBUG_STDOUT):
                print "UploadUnsentFILES(): folderPathName = %s." % folderPathName
                sys.stdout.flush()

            if os.path.isdir(folderPathName):
                UploadUnsentFolder(folderName, folderPathName) #folderContent[i] is the aDeviceId
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def StoreStateCamAutoCfgWinCE():
    if (MY_DEBUG_STDOUT):
        print "Entered StoreStateCamAutoCfgWinCE()."
        sys.stdout.flush()

    try:
        fOutput = open(LOCAL_FOLDER + "/CamAuto.cfg", "wb")
        fOutput.write("%d %d" % (videoRecordDuration[0], pauseInterval))
        fOutput.close()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


STORE_STATE = True
def StoreState():
    global STORE_STATE, deviceId

    try:
        if (STORE_STATE):
            UploadStateAndFileAndStoreState(deviceId, None, None, -1, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE)
            #UploadStateAndFileAndStoreState(None) #fileName = None; maybe set also inetServerAddress, pageOnServer
            if (MY_DEBUG_STDOUT):
                print "StoreState(): Wrote state file."
                sys.stdout.flush()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


###############################################################################
###############################################################################
###############################################################################
###############################################################################
##############################Bluetooth########################################
###############################################################################
###############################################################################
###############################################################################
###############################################################################
bluetoothModeList = [
                #u"No Bluetooth",
                u"Bluetooth not used",
                u"Bluetooth server and Internet proxy", #basestation
                u"Bluetooth client"
]
bluetoothFormSaved = False #This var is required as global.
def SelectBluetoothMode(): #Uses a Form
    global bluetoothMode, bluetoothServerAddress
    global bluetoothFormSaved

    pass



###############################################################################
###############################################################################
###############################################################################
###############################################################################
##########################End Bluetooth########################################
###############################################################################
###############################################################################
###############################################################################
###############################################################################



def SetLocalPhotoResolution():
    pass

def Help():
    pass

def ConfirmQuit():
    pass


"""
*args is for the Android callback
See http://docs.python.org/release/2.5.2/ref/function.html :
    "If the form ``*identifier'' is present, it is initialized to a tuple receiving any excess positional parameters, defaulting to the empty tuple. If the form ``**identifier'' is present, it is initialized to a new dictionary receiving any excess keyword arguments, defaulting to a new empty dictionary."
  See also http://stackoverflow.com/questions/400739/what-does-mean-in-python .
"""
def Quit(*args):
    global stdoutFile, stderrFile, deviceId
    global appLock

    if (iOS_PYOBJC):
        try:
            if (MY_DEBUG_STDOUT):
                stdoutFile.close()
            if (MY_DEBUG_STDERR):
                stderrFile.close()
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

        """
        From http://docs.python.org/library/exceptions.html#exceptions.SystemExit 
        "This exception is raised by the sys.exit() function. When it is not handled, the Python interpreter exits; no stack traceback is printed."
        "The os._exit() function can be used if it is absolutely positively necessary to exit immediately (for example, in the child process after a call to fork())"
        """
        #sys.exit() #This doesn't work well because I'm catching exceptions in the caller of Quit(), namely EventHandler().

        #See http://docs.python.org/library/os.html
        os._exit(0)


def PlayAudioFile(pathFileName):
    #!!!!!to implement
    return


def StartGPS():
    global readGPS

    pass


def StopGPS():
    global readGPS

    try:
        readGPS = 0 #False
        if (MY_DEBUG_STDOUT):
            print "StopGPS(): readGPS = %d." % readGPS
            sys.stdout.flush()
        SetMenu()
        StoreState()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


#viewFinderTimer = e32.Ao_timer()
#viewFinderTimerIsOn = False
startedReceivingFramesFromViewFinder = False
fillColorText = 0xFF0000
prevVFFrame = None
counterViewFinderCallBack = 0
#On N82 (probably on N95 as well) if the viewfinder is started, but I give an ao_sleep() it appears the Main camera shutter gets closed even if the viewfinder is started.

videoRecordFPS = 15

lastTimeAdapted = -1
numFramesLastTimeAdapted = 0

videoRecordStartTime = -1 #None
#videoRecordStartTime = time.time()
videoRecordTime = 0

viewFinderStartTime = 0
avgFPS = 0.0

numFrames = 0

pauseFormSaved = False #This var is required as global.
def PauseIntervalMenu(*args): #Uses a Form
    global pauseFormSaved
    global pauseInterval

    pass


#These functions set the capture time interval, the number of cameras used, resolution, zoom and photo (JPEG) quality to the selected value.
def SetPauseInterval_real(aPauseInterval):
    global pauseIntervalStr, pauseInterval, MENU_SELECT_PREFIX
    global reactiveLoopIsStarted, burstModeIsStarted

    if (MY_DEBUG_STDOUT):
        print "SetPauseInterval_real(): pauseInterval = %d, aPauseInterval = %d, len(pauseIntervalStr) = %d." % (pauseInterval, aPauseInterval, len(pauseIntervalStr))
        sys.stdout.flush()

    pauseInterval = aPauseInterval
    #SetMenu()
    StoreState()
    #UploadText("New photo interval: %d." % pauseInterval, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT) #This might be the reason my app crashed.

    if (pauseInterval == 0):
        if ((reactiveLoopIsStarted == True) and (cameraMode[0] * cameraMode[1] == 0) and (cameraMode[0] + cameraMode[1] > 0)):
            SetRecordDuration(0, 0)
            SetRecordDuration(1, 0)
            SetRecordDuration(2, 0)
            StartBurstMode()
    else:
        if (burstModeIsStarted == True):
        #if (reactiveLoopIsStarted == True):
            StopBurstMode()
            ReactiveLoop()
#We define this function as 2 lambdas to make it an callable even if it is passed the aPauseInterval parameter.
SetPauseInterval = lambda aPauseInterval: (lambda : SetPauseInterval_real(aPauseInterval))


def SetUploadedPhotoResolutionIndex_real(aResolutionIndex):
    global photoResolutionStr, photoResolutionIndex, MENU_SELECT_PREFIX

    if (MY_DEBUG_STDOUT):
        print "SetUploadedPhotoResolutionIndex_real(): aResolutionIndex = %d." % (aResolutionIndex)
        sys.stdout.flush()

    if (aResolutionIndex < 0 or aResolutionIndex >= len(photoResolutionStr)):
        return
    """
    if (photoResolutionStr[photoResolutionIndex][0][0:len(MENU_SELECT_PREFIX)] == MENU_SELECT_PREFIX):
        photoResolutionStr[photoResolutionIndex][0] = photoResolutionStr[photoResolutionIndex][0][len(MENU_SELECT_PREFIX):]
    photoResolutionStr[aResolutionIndex][0] = MENU_SELECT_PREFIX + photoResolutionStr[aResolutionIndex][0]
    """
    photoResolutionIndex = aResolutionIndex

    """
    global viewFinderSize
    viewFinderSize = photoResolutionStr[photoResolutionIndex][1]
    """

    #SetMenu()
    StoreState()
#We define this function as 2 lambdas to make it an callable even if it is passed the aResolutionIndex parameter.
SetUploadedPhotoResolutionIndex = lambda aResolutionIndex: (lambda : SetUploadedPhotoResolutionIndex_real(aResolutionIndex))


def SetLocalPhotoResolutionIndex(aLocalPhotoResolutionIndex): #!!!!currently only for Main camera. Add for VGA camera, as well
    global localPhotoResolutionIndex, cameraPhotoSizes_JPEG_Exif, MENU_SELECT_PREFIX

    if (MY_DEBUG_STDOUT):
        print "SetLocalPhotoResolutionIndex_real(): aLocalPhotoResolutionIndex = %d." % (aLocalPhotoResolutionIndex)
        sys.stdout.flush()

    if (aLocalPhotoResolutionIndex < 0 or aLocalPhotoResolutionIndex >= len(cameraPhotoSizes_JPEG_Exif[0])):
        return
    localPhotoResolutionIndex[0] = aLocalPhotoResolutionIndex
    if (MY_DEBUG_STDOUT):
        print "SetLocalPhotoResolutionIndex_real(): made localPhotoResolutionIndex[0] = %d." % (aLocalPhotoResolutionIndex)
        sys.stdout.flush()
    #SetMenu()
    StoreState()
    SetLocalPhotoResolution()


#I keep this one because we use it on Android
def SelectStoreLocallyMediaMenu():
    global storeLocallyMedia, MENU_SELECT_PREFIX

    TITLE_MENU = u"Media Storage"

    storeLocallyMediaStr = [
                    "Do not store media",
                    "Store all media"
    ]
    #!!!!Can have also "Store only movies", "Store only photos"; also "Store only 1 media file every 5", etc.

    popupMenuList = []
    for i in range(len(storeLocallyMediaStr)):
        if (i == storeLocallyMedia):
            popupMenuList += [unicode(MENU_SELECT_PREFIX + storeLocallyMediaStr[i])]
        else:
            popupMenuList += [unicode(storeLocallyMediaStr[i])]

    if (resMenu == None):
        return
    else:
        storeLocallyMedia = resMenu
    StoreState()


def SetDigitalZoom_real(aDigitalZoom):
    global digitalZoom

    if (MY_DEBUG_STDOUT):
        print "SetDigitalZoom_real(): aDigitalZoom = %d." % (aDigitalZoom)
        sys.stdout.flush()

    digitalZoom = aDigitalZoom
    #StartViewFinderForCamera(0, True, True)
    #SetMenu()
    StoreState()
#We define this function as 2 lambdas to make it an callable even if it is passed the aDigitalZoom parameter.
SetDigitalZoom = lambda aDigitalZoom: (lambda : SetDigitalZoom_real(aDigitalZoom))


def SetRecordDuration(cameraId, aRecordDuration): #If cameraId == 2 then it means audioRecordDuration.
    global videoRecordDuration, audioRecordDuration

    if (MY_DEBUG_STDOUT):
        print "SetRecordDuration(): cameraId = %d, aRecordDuration = %d." % (cameraId, aRecordDuration)
        sys.stdout.flush()

    if (aRecordDuration < 0):
        return

    if (cameraId == 0 or cameraId == 1):
        videoRecordDuration[cameraId] = aRecordDuration
    elif (cameraId == 2):
        audioRecordDuration = aRecordDuration

    StoreState()


def SetRecordDurationMenu_real(cameraId): #If cameraId == 2 then it means audioRecordDuration.
    global videoRecordDuration, audioRecordDuration

    if (MY_DEBUG_STDOUT):
        print "Entered SetRecordDurationMenu_real(cameraId = %d)." % (cameraId)
        sys.stdout.flush()

    if (cameraId == 0 or cameraId == 1):
        myText = "Video Record Duration (" + ["Main", "VGA"][cameraId] + " Camera):"
        initVal = videoRecordDuration[cameraId]
    elif (cameraId == 2):
        myText = "Audio Record Duration:"
        initVal = audioRecordDuration

    #SetMenu()
    SetRecordDuration(cameraId, res)
    StoreState()
SetRecordDurationMenu = lambda cameraId: (lambda : SetRecordDurationMenu_real(cameraId))


durationFormSaved = False #This var is required as global.
def RecordConfigMenu():
    global durationFormSaved
    global audioRecordDuration, videoRecordDuration, videoAudioEnabled
    global localVideoModeIndex, localVideoMode

    yesNoComboList = [u"No", u"Yes"]


cameraModesFormSaved = False #This var is required as global.
def CaptureWhatMenu():
    global cameraModesFormSaved
    global cameraMode, readGPS, logAccelerometerAndRotationSensors

    #From http://wiki.forum.nokia.com/index.php/How_to_use_Form_in_Python_for_S60 (and also http://www.mobilenin.com/pys60/info_tabs_forms.htm):
    TITLE_MENU = u"Capture What" #u"Media Storage"

    cameraModesComboList = [u"None", u"Video", u"Photo", u"Both photo and video"]
    microphoneComboList = [u"[Select duration from Record Config]"]


def SetPhotoQuality_real(aQuality):
    global photoQuality
    if (aQuality < 0 or aQuality > 100):
        return
    photoQuality = aQuality
    #SetMenu()
    StoreState()
#We define this function as 2 lambdas to make it an callable even if it is passed the aQualityIndex parameter.
SetPhotoQuality = lambda aQuality: (lambda : SetPhotoQuality_real(aQuality))


photoFormSaved = False #This var is required as global.
def PhotoConfigMenu():
    global photoFormSaved
    global localPhotoResolutionIndex, photoResolutionIndex, photoQuality

    if (MY_DEBUG_STDOUT):
        print "Entered PhotoConfigMenu()."
        sys.stdout.flush()


def UploadInboxSMSes(cleanUndesiredSMSes = False):
    global deviceId
    global inboxIsImported

    if (MY_DEBUG_STDOUT):
        print "Entered UploadInboxSMSes(): inboxIsImported = %d." % inboxIsImported
        sys.stdout.flush()


#Not sure why I really need this - probably to receive a .WAV file from the server to be played on the phone
#script (e.g., an updated iCam.Py script) and run it, an extension, etc.
def DownloadFile(fileName):
    global PHP_SERVER_NAME, accessPointName
    global deviceId

    if (NoInternetConnection()):
        return

    try:
        PetWatchdog()
        dataCompressed = urllib.urlopen("http://" + PHP_SERVER_NAME + WEBPAGE_DL_GZIPPED_FILE + "?deviceId=" + deviceId + "&filename=" + fileName).read()
        dataUncompressed = dataCompressed.decode("zlib")

        LOCAL_FOLDER_FILES_FROM_SERVER = LOCAL_FOLDER + "/FilesFromServer"
        try:
            if (not os.path.exists(LOCAL_FOLDER_FILES_FROM_SERVER)):
                os.makedirs(LOCAL_FOLDER_FILES_FROM_SERVER)
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

        fOutput = open(LOCAL_FOLDER_FILES_FROM_SERVER + "/" + fileName, "wb")
        fOutput.write(dataUncompressed)
        fOutput.close()
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        myText = "Exception in DownloadFile. Details: time = %s, free_ram = %d. %s." % (GetCurrentDateTimeStringNice(), GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)) )
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
        if (MY_DEBUG_STDOUT):
            print myText
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            #traceback.print_exc()
            sys.stderr.write(myText + "\n")
            sys.stderr.flush()


"""
Change User-Agent (see http://docs.python.org/library/urllib.html and http://diveintopython3.org/http-web-services.html). 
By default urllib.urlopen sends a User-Agent string "Python-urllib/1.17" (see /var/log/apache2/access.log for log entries when it calls cmd.php).
"""
class AppURLopener(urllib.FancyURLopener):
    version = ""
urllib._urlopener = AppURLopener()


def ExecuteCommands(cmdString):
    global MY_DEBUG_STDOUT, MY_DEBUG_STDERR, MY_DEBUG_STDERR_2, MY_DEBUG_UPLOAD_MSG
    global MAX_NUM_HOTSPOTS
    global deviceId, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT
    global modeManagerIsEnabled

    if (len(cmdString) < 5):
        return False

    myText = "ExecuteCommands(): Received commands at %s: %s." % (GetCurrentDateTimeStringNice(), cmdString)

    if (MY_DEBUG_STDOUT):
        print myText
        sys.stdout.flush()

    if (MY_DEBUG_UPLOAD_MSG):
        UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

    try:
        lineList = cmdString.splitlines()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
        return False

    #res = 0

    cmdIterator = lineList.__iter__()

    #Python doesn't have hasNext() method - see http://stackoverflow.com/questions/1966591/hasnext-in-python-iterators
    while (cmdIterator.__length_hint__() > 0):
        try:
            cmdLine = cmdIterator.next()
            #print cmdIterator.__length_hint__()
            tokens = cmdLine.split(" ")

            if (MY_DEBUG_STDOUT):
                print "ExecuteCommands(): tokens = %s." % str(tokens)
                sys.stdout.flush()

            if   (tokens[0] == "quit-application"):
                Quit()
            elif (tokens[0] == "restart-phone"):
                RestartPhone()
            elif (tokens[0] == "set-startAutomatically"):
                pass
                """
                #I think it is not a good idea to do have it since we don't want to give the possibility to control remotely the device.
                    global startAutomatically
                    startAutomatically = int(tokens[1])
                """
            elif (tokens[0] == "set-internetUploadMaxErrors"):
                global internetUploadMaxErrors
                internetUploadMaxErrors = int(tokens[1])
            elif (tokens[0] == "set-NUM_UNSENT_PACKETS_BEFORE_DOWNLOAD_COMMANDS"):
                global NUM_UNSENT_PACKETS_BEFORE_DOWNLOAD_COMMANDS
                NUM_UNSENT_PACKETS_BEFORE_DOWNLOAD_COMMANDS = int(tokens[1])
            elif (tokens[0] == "set-uploadUnsentData"): #0 - send none; 1 - send unsent files from Unsent; 2 - send unsent logs; 3 - send ALL
                global uploadUnsentData
                uploadUnsentData = int(tokens[1])
            elif (tokens[0] == "set-saveUnsentPackets"): #0 - send none; 1 - send unsent files from Unsent; 2 - send unsent logs; 3 - send ALL
                global saveUnsentPackets
                saveUnsentPackets = int(tokens[1])
            elif (tokens[0] == "upload-how-many-of-latest-bluetooth-messages"): #if 0 don't upload, if -1 upload all, if > 0 then upload that many latest.
                global uploadHowManyOfLatestBluetoothMessages
                uploadHowManyOfLatestBluetoothMessages = int(tokens[1])
            elif (tokens[0] == "send-command-via-bluetooth"):
                BluetoothClientDiscoverServer(tokens[1])
                BluetoothUploadGZippedData(tokens[1], cmdLine[len(tokens[0]) + len(tokens[1]) + 2 : ], COMMANDS_FILENAME)
                #print tokens[2:]
            elif (tokens[0] == "send-commands-via-bluetooth"):
                #print tokens[2:]
                btCmd = cmdLine[len(tokens[0]) + len(tokens[1]) + 2 : ]
                #print "Initially btCmd =", btCmd
                while (cmdIterator.__length_hint__() > 0):
                    cmdLineNew = cmdIterator.next()
                    if (cmdLineNew == "send-commands-via-bluetooth-endline"):
                        break
                    else:
                        btCmd += "\n" + cmdLineNew
                if (MY_DEBUG_STDOUT):
                    print "ExecuteCommands(): btCmd = %s." % btCmd
                    sys.stdout.flush()
                BluetoothClientDiscoverServer(tokens[1])
                BluetoothUploadGZippedData(tokens[1], btCmd, COMMANDS_FILENAME)
            elif (tokens[0] == "set-logging-level"):
                MY_DEBUG_STDOUT = int(tokens[1])
                MY_DEBUG_STDERR = int(tokens[2])
                MY_DEBUG_STDERR_2 = int(tokens[3])
                MY_DEBUG_UPLOAD_MSG = int(tokens[4])
            elif (tokens[0] == "set-pause-interval"):
                #myTimer.cancel()
                SetPauseInterval( int(tokens[1]) )()
                #res = 1
            elif (tokens[0] == "set-pauseIntervalBetweenGoogleGdataMediaUploads"):
                global pauseIntervalBetweenGoogleGdataMediaUploads
                pauseIntervalBetweenGoogleGdataMediaUploads = int(tokens[1])
            elif (tokens[0] == "set-battery-level-threshold"):
                global BATTERY_LEVEL_THRESHOLD
                BATTERY_LEVEL_THRESHOLD = int(tokens[1])
            elif (tokens[0] == "set-camera-mode"):
                global cameraMode
                cameraMode[int(tokens[1])] = int(tokens[2]) #0 = None, 1 = Only Video, 2 = Only Photo, 3 = Both Photo and Video
            elif (tokens[0] == "set-photo-resolution-index"):
                SetUploadedPhotoResolutionIndex( int(tokens[1]) )()
            elif (tokens[0] == "set-photo-quality"):
                SetPhotoQuality( int(tokens[1]) )()
            elif (tokens[0] == "set-photo-mode-index"):
                #!!!!!!!!!!!!!!!!!!!!!!
                pass
            elif (tokens[0] == "set-digital-zoom"):
                SetDigitalZoom( int(tokens[1]) )()
            elif (tokens[0] == "set-camera-exposure-index"):
                global exposureIndex
                #!!!!correct - use functions
                cameraId = int(tokens[1])
                exposureIndex[cameraId] = int(tokens[2])
            elif (tokens[0] == "set-camera-whitebalance-index"):
                global whiteBalanceIndex
                cameraId = int(tokens[1])
                whiteBalanceIndex[cameraId] = int(tokens[2])
            elif (tokens[0] == "set-flash-index"):
                global flashIndex
                flashIndex = int(tokens[1])
            elif (tokens[0] == "set-camera-video-record-duration"):
                cameraId = int(tokens[1])
                SetRecordDuration(cameraId, int(tokens[2]))
            elif (tokens[0] == "set-video-mute"):
                global videoAudioEnabled
                videoAudioEnabled = 1 - int(tokens[1])
                if (MY_DEBUG_STDOUT):
                    print "ExecuteCommands(): made videoAudioEnabled = %d." % videoAudioEnabled
                    sys.stdout.flush()
            elif (tokens[0] == "set-local-video-mode-index"):
                global localVideoModeIndex, localVideoMode, cameraVideoModes
                cameraId = int(tokens[1])
                localVideoModeIndex[cameraId] = int(tokens[2])
                #localVideoMode[cameraId] = cameraVideoModes[localVideoModeIndex[cameraId]]
                """
                localVideoMode[cameraId][0] = cameraVideoModes[cameraId][localVideoModeIndex[cameraId]]["size"]
                localVideoMode[cameraId][1] = cameraVideoModes[cameraId][localVideoModeIndex[cameraId]]["rate"]
                """
                localVideoMode[cameraId] = (cameraVideoModes[cameraId][localVideoModeIndex[cameraId]]["size"], cameraVideoModes[cameraId][localVideoModeIndex[cameraId]]["rate"])

                #SetLocalPhotoResolution()
            elif (tokens[0] == "set-local-photo-resolution-index"):
                global localPhotoResolutionIndex
                cameraId = int(tokens[1])
                localPhotoResolutionIndex[cameraId] = int(tokens[2])
                SetLocalPhotoResolution()
            elif (tokens[0] == "set-audio-record-duration"):
                SetRecordDuration(2, int(tokens[1]))

            elif (tokens[0] == "set-bluetooth-mode"):
                global bluetoothMode
                bluetoothMode = int(tokens[1])
            elif (tokens[0] == "upload-file"):
                UploadFile(tokens[1], PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_FILE)
            elif (tokens[0] == "upload-inbox-smses"):
                if (len(tokens) > 1 and tokens[1] == "and-clean-undesired-smses"):
                #if (tokens[1] == "and-clean-undesired-smses"):
                    UploadInboxSMSes(True)
                else:
                    UploadInboxSMSes(False)
            elif (tokens[0] == "retrieve-gps-coordinates"):
                StartGPS()
            elif (tokens[0] == "download-file"):
                DownloadFile(tokens[1])
            elif (tokens[0] == "play-audio-file"):
                soundRecord = audio.Sound.open(unicode(tokens[1]))

                if (MY_DEBUG_STDOUT):
                    print "ExecuteCommands(): play-audio-file - starting to play file %s of size %.2f" % (tokens[1], float(soundRecord.duration()) / 1000000)
                    sys.stdout.flush()
                #PlayAudioFile()
                soundRecord.play()
                #soundRecord.play(times=1, interval=0, callback=validate)
                #play([times=1, interval=0, callback=None]) #If the audio file is played several times, interval gives the time interval between the subsequent plays in microseconds.

                #This is required because otherwise the file stops playing (probably because of SetMenu() at the end of this function).
                SleepAndPetWatchdog( (soundRecord.duration() + 500000) / 1000000)

                #Inspired from Z:\1PhD\ReVival\111111111Src_examples\PyS60_2_0_0\winscw\c\data\python\test\test_audio.py
                """
                max_volume = self.sound_object.max_volume()
                set_volume = max_volume - 2
                self.sound_object.set_volume(set_volume)
                """

                """
                time_of_playback = self.sound_object.duration()
                # Subtract 3 seconds(expressed in micro seconds) from the total
                # duration of the track and start playback from this position.
                start_position = time_of_playback - 3000000L
                self.sound_object.set_position(start_position)
                """
            elif (tokens[0] == "set-server"):
                PHP_SERVER_NAME = tokens[1]

            elif (tokens[0] == "get-date-and-time"):
                myText = "Date and time is: " + GetCurrentDateTimeStringWithMilliseconds() + "."
                #if (MY_DEBUG_UPLOAD_MSG):
                UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
                #IMPORTANT NOTE: We can also get the date and time by looking at a (preferably small packet) received at UploadGzippedStateAndFile.php (or even with UploadGzippedText.php).
            elif (tokens[0] == "set-date-and-time"):
                pass
            elif (tokens[0] == "adjust-date-and-time-using-delta"):
                #On S60 3rd+ edition we need WriteDeviceData capabilities (which implies we have to sign with dev certificate) - See http://discussion.forum.nokia.com/forum/showthread.php?119016-e32.set_home_time%20%20-fails-on-real-device#903719400565939968.
                myTime = time.time() + int(tokens[1]) #Inspired from http://discussion.forum.nokia.com/forum/showthread.php?119016-e32.set_home_time%20%20-fails-on-real-device#32583428368845857418
                #myTime = FromStringToTime(tokens[1])
                #myTime = tokens[1]

                pass
            elif (tokens[0] == "set-burst-detection"):
                burstModeIsStarted = int(tokens[1])
            elif (tokens[0] == "set-motion-detection-number-hotspots"):
                global numHotspots
                numHotspots = int(tokens[1])
                if (numHotspots > MAX_NUM_HOTSPOTS):
                    return
            elif (tokens[0] == "set-different-pixels-percentage-threshold"):
                global differentPixelsPercentageThreshold
                hotspotIndex = int(tokens[1])
                if (hotspotIndex >= MAX_NUM_HOTSPOTS):
                    return
                differentPixelsPercentageThreshold[0] = int(tokens[2])
            elif (tokens[0] == "set-motion-detection-hotspot"):
                global hotspot
                hotspotIndex = int(tokens[1])
                SetMotionDetectionHotspot(hotspotIndex, int(tokens[2]), int(tokens[3]), int(tokens[4]), int(tokens[5]))

            elif (tokens[0] == "set-store-locally-media"):
                global storeLocallyMedia
                storeLocallyMedia = int(tokens[1])

            elif (tokens[0] == "set-upload-media-to"):
                global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer
                uploadMediaToYouTube = int(tokens[1])
                uploadMediaToPicasa = int(tokens[2])
                uploadMediaToiCamServer = int(tokens[3])
                StoreLocalStateInFile()
            elif (tokens[0] == "set-google-username"):
                global googleUsername
                googleUsername = tokens[1]
                StoreLocalStateInFile()
            elif (tokens[0] == "set-google-password-encrypted"):
                global googlePasswordEncrypted
                googlePasswordEncrypted = tokens[1]
                StoreLocalStateInFile()

            elif (tokens[0] == "erase-oldest-files-and-messages"):
                EraseOldestFilesAndMessages()

            elif (tokens[0] == "set-mode-manager"):
                modeManagerIsEnabled = int(tokens[1])
            elif (tokens[0] == "set-dawn-time"):
                global dawnTimeVec
                timeTokens = tokens[1].split(":") #hh:mm:ss
                dawnTimeVec = [int(timeTokens[0]), int(timeTokens[1]), int(timeTokens[2])]
            elif (tokens[0] == "set-dusk-time"):
                global duskTimeVec
                timeTokens = tokens[1].split(":") #hh:mm:ss
                duskTimeVec = [int(timeTokens[0]), int(timeTokens[1]), int(timeTokens[2])]

            elif (tokens[0] == "exec-security-issues"): #"exec-security-issues-no-stdouterr"):
                #IMPORTANT TODO: !!!!check for dangerous commands
                #See http://stackoverflow.com/questions/701802/how-do-i-execute-a-string-containing-python-code-in-python.
                #"eval returns a value, but doesn't work for all commands. exec works for all, but doesn't return a value. Still trying to figure out a way around this"
                #!!!!"Another solution is to write that string to a temporary python file and execute it."
                myExecResult = ""
                #exec tokens[1]
                exec cmdLine[len(tokens[0]) + 1 : ] #We can put spaces in the commands following the exec-... keyword.

                myText = "myExecResult = %s" % str(myExecResult)
                UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
                if (MY_DEBUG_STDOUT):
                    print myText
                    sys.stdout.flush()
            """
            elif (tokens[0] == "get-phone-model-and-number"):
                PHONE_INFO_FILENAME = LOCAL_FOLDER + "/PhoneInfo.txt"
                fOutput = open(PHONE_INFO_FILENAME, "wb")
                fOutput.write("blabla")
                fOutput.close()                    
                UploadFile(PHONE_INFO_FILENAME, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_FILE)
            #elif (tokens[0] == "set-access-point"):
            #elif (tokens[0] == "get-phone-number"):
            #http://docs.python.org/library/urllib.html
            """
        except:
            exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
            myText = "Exception in ExecuteCommands(). Details: time = %s, free_ram = %d. exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s." % (GetCurrentDateTimeStringNice(), GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )
            if (MY_DEBUG_UPLOAD_MSG):
                UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
            if (MY_DEBUG_STDOUT):
                #sys.stderr.write(myText + "\n")
                print myText
                sys.stdout.flush()
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()
            #return False

    #!!!!I should check if you have performed operations that affect the UI
    SetMenu()
    StoreState()

    return True


"""
Where to write the iCam commands in YouTube?
    - I googled to see if I can store an arbitrary file on YouTube - I didn't find anything. Only about storing on Gmail - but this is an unnecessary complication.

    - I use description in
        - playlist - a bit more difficult to read, but possible to write with Gdata
            - disadvantage - the playlist can be erased...
        - MAYBE in some video

    - other possible ideas to implement:
        - I can use "user profile" - very simple to read, seems impossible to write with Gdata
            - we can keep locally on the phone (iCam.py) track of the fact we downloaded command
            - https://code.google.com/apis/youtube/2.0/developers_guide_protocol.html#Profiles
                "The YouTube Data API allows you to retrieve user profiles."

              def GetYouTubeUserEntry(self, uri=None, username=None):
                Retrieve a YouTubeUserEntry.

            - to make certain fields in user profile private go to:
                - http://www.youtube.com/profile?user=sgs637#g/f - give edit on profile and deselect the ones you don't want to make public ;)
                - http://www.youtube.com/account_privacy

        - https://sites.google.com/site/sgs637/
            It seems there is no GData API for YT Messages http://www.youtube.com/inbox?folder=messages&action_message=1&authuser=0#inbox/1
                Note: I can send myself messages.

        - other APIs that can be explored:
            Running all tests in module gdata_tests.docs_test
            Running all tests in module gdata_tests.health_test
            Running all tests in module gdata_tests.spreadsheet_test
            Running all tests in module gdata_tests.blogger_test
            Running all tests in module gdata_tests.webmastertools_test

        - I probably cannot write commands in a file and pretend it's a video since YouTube will discard the video as invalid.
            - more complicated embeddings of commands in a real video are not very appropriate - for phone I guess it would be harder to decode them.

"""
def DownloadCommandsFromYouTube():
    try:
        if (MY_DEBUG_STDOUT):
            print "Entered DownloadCommandsFromYouTube(): uploadMediaToYouTube = %d." % uploadMediaToYouTube
            sys.stdout.flush()

        if (uploadMediaToYouTube == False):            
            """
            if (MY_DEBUG_STDOUT):
                print "DownloadCommandsFromYouTube(): bailing out."
                sys.stdout.flush()
            """
            return ""

        if (youtubeClientAlreadyConnected == False):
            if (gdataModulesImported == False):
                ImportGdataModules()
            connResult = ConnectToYouTubeGData()
            #If connResult == -1 then don't continue (most likely bad username/passwd).!!!!

        playlistTitle = "iCam_cmd_" + deviceId
        playlistDescription = ""
        
        playlistToUse = None
        #feed = youtubeClient.GetYouTubePlaylistFeed(username = "MultiEnder123") #username='ender123') #!!!!We require the YouTube alias/nickname which can be different to the Google username!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        feed = youtubeClient.GetYouTubePlaylistFeed() #!!!!You need to get all playlists - I think it returns only first 25!!!!
        #Returns: A YouTubePlaylistFeed if successfully retrieved.
        #print "DownloadCommandsFromYouTube(): feed = %s" % str(feed)
        #print "feed.entry[0] =", feed.entry[0]
        for myEntry in feed.entry:
            myEntryTitle = myEntry.title.text
            #print "myEntryTitle = %s" % myEntryTitle

            #myEntry.id.text = http://gdata.youtube.com/feeds/api/users/MultiEnder123/playlists/3FD3773F7AC5DD1E
            #myEntry.id = <xml>...
            myEntryIdStr = myEntry.id.text.split("/")[-1]
            #print "  myEntryIdStr = %s" % myEntryIdStr

            if (myEntryTitle == playlistTitle):
                if (MY_DEBUG_STDOUT):
                    print "DownloadCommandsFromYouTube(): Feed matched myEntry =", myEntry
                    print "DownloadCommandsFromYouTube(): myEntry.content =", myEntry.content
                    print "DownloadCommandsFromYouTube(): myEntry.description = %s" % str(myEntry.description)
                    sys.stdout.flush()

                #playlistDescription = myEntry.description.split("/")[-1]
                playlistDescription = str(myEntry.description).split(">")[-2].split("</")[0]
                if (MY_DEBUG_STDOUT):
                    print "DownloadCommandsFromYouTube(): playlistDescription =", playlistDescription
                    sys.stdout.flush()

                playlistToUse = myEntry
                break

        if (playlistDescription != ""):
            #Erase the freshly downloaded commands from YouTube
            youtubeClient.UpdatePlaylist(playlist_id = myEntryIdStr, new_playlist_title = playlistTitle, new_playlist_description = "", playlist_private = True, username = "default")

        return playlistDescription

        """
        if (playlistToUse == None):
            #Create the playlist if it was not found
            playlistToUse = youtubeClient.AddPlaylist(playlistTitle, playlistTitle, playlist_private = True) #Returns: The YouTubePlaylistEntry if successfully posted.

        aVideoTitle = "" #It seems this info is not used!
        aVideoDescription = "" #It seems this info is not used!
        playlistURI = playlistToUse.feed_link[0].href
        #time.sleep(10) #!!!!!!!!!!!!!Maybe required
        response = youtubeClient.AddPlaylistVideoEntryToPlaylist(playlistURI, newVideoEntry.id.text.split('/')[-1], aVideoTitle, aVideoDescription)
        """

        #newVideoEntry = youtubeClient.InsertVideoEntry(videoEntry, pathFileName)
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        errorStr = "Exception in DownloadCommandsFromYouTube() - details: exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s. Bailing out..." % ( repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )

        if (MY_DEBUG_STDOUT):
            print errorStr
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

        return ""


downloadCommandsCounter = 0
def DownloadCommands_real():
    global deviceId
    global PHP_SERVER_NAME
    global accessPointNotConnectedTo, accessPointName
    global uploadMediaToYouTube
    global downloadCommandsCounter

    if (MY_DEBUG_STDOUT):
        print "Entered DownloadCommands(): accessPointName = %s." % accessPointName
        sys.stdout.flush()

    pathFileName = LOCAL_FOLDER + "/" + COMMANDS_FILENAME
    if (os.path.isfile(pathFileName)):
        try:
            fInput = open(pathFileName, "rb")
            myCommands = fInput.read()
            fInput.close()
            os.unlink(pathFileName) #Should I delete pathFileName after ExecuteCommands(myCommands)? !!!!
        except:
            if (MY_DEBUG_STDOUT):
                traceback.print_exc()
                sys.stderr.flush()
        return ExecuteCommands(myCommands)

    if (NoInternetConnection()):
        if (MY_DEBUG_STDOUT):
            print "DownloadCommands(): Not downloading commands since there is no Internet connection."
            sys.stdout.flush()
        return False

    try:
        if (iOS_PYOBJC and MY_DEBUG_STDOUT):
            print "DownloadCommands(): Before urllib.urlopen()."
            sys.stdout.flush()
            #urllib.urlopen() seems to crash the application...

        if (uploadMediaToYouTube):
            if (downloadCommandsCounter == 0):
                myCommands = DownloadCommandsFromYouTube() #GetYouTubeUserProfile()
                if (myCommands != ""):
                    return ExecuteCommands(myCommands)

        downloadCommandsCounter += 1
        if (downloadCommandsCounter == 5):
            downloadCommandsCounter = 0

        myCommandsCompressed = urllib.urlopen("http://" + PHP_SERVER_NAME + WEBPAGE_DL_COMMAND_FILE + "?deviceId=" + deviceId).read()
        myCommands = myCommandsCompressed.decode("zlib")

        if (iOS_PYOBJC and MY_DEBUG_STDOUT):
            print "DownloadCommands(): After urllib.urlopen()."
            sys.stdout.flush()

        return ExecuteCommands(myCommands)
    #except IOError:
    #    print "DownloadCommands IOError"
    #    traceback.print_exc()
    #    sys.stderr.flush()
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        myText = "Exception in DownloadCommands. Details: time = %s, free_ram = %d. exceptionTraceback = %s, exceptionType = %s, exceptionValue = %s." % (GetCurrentDateTimeStringNice(), GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)), str(exceptionType), str(exceptionValue) )
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
        if (MY_DEBUG_STDOUT):
            #sys.stderr.write(myText + "\n")
            print myText
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
        return False
    #UploadText("Read command file.", PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT)

    #return res

"""
!!!!Although we give hasDownloadedNewCmd = DownloadCommands() and we do not use hasDownloadedNewCmd anywhere at all,
we should maybe return result from the function, as it was doing the original DownloadCommands()
"""
def DownloadCommands():
    DownloadCommands_real()
    #thread.start_new_thread(ReactiveLoop_real, ())
    #MyThreadStart(DownloadCommands_real)


#In order for the viewfinder to correspond to the zoom level, we must take a picture (without saving it), close and open the viewfinder.
#These steps are necessary because of the way the functions are currently defined in PyS60, and have a slight impact on performance.
#Future releases of PyS60 may have optimized functions.
#pic = camera.take_photo('RGB', cameraPhotoSizes[1], digitalZoom, 'none', 'auto', 'auto', 0)  #Take the picture with cameraId = 0
#camera.stop_finder()
#camera.start_finder(ViewFinderCallBack, backlight_on = 1, size = (240,180))


def GetTextForState(cameraId):
    resText = ""
    try:
        resText = "Free space in bytes on drives: C = %d, D = %d, E = %d. " % (GetFreeDriveSpace("C:"), GetFreeDriveSpace("D:"), GetFreeDriveSpace("E:"))
        resText += "free_ram = %d. GSM network signal strength = %d [%s]. Battery = %d, charger_status = %d. Pause interval (pauseInterval) = %d. Camera modes = (%d, %d). " % (GetFreeRAM(), signalStrength, signalUnits, GetBatteryLevelPercentage(), GetChargerStatus(), pauseInterval, cameraMode[0], cameraMode[1])
        resText += "Resolution (photoResolutionIndex) = %d. photoModeIndex = %d. digitalZoom = %d. photoQuality = %d. exposureIndex[0] = %d. " % (photoResolutionIndex, photoModeIndex[cameraId], digitalZoom, photoQuality, exposureIndex[0])
        resText += "whiteBalanceIndex[0] = %d. exposureIndex[1] = %d. whiteBalanceIndex[1] = %d. flashIndex = %d. audioRecordDuration = %d. " % (whiteBalanceIndex[0], exposureIndex[1], whiteBalanceIndex[1], flashIndex, audioRecordDuration)
        resText += "rotateDegreesImage = %d. mobileCountryCode = %d. mobileNetworkCode = %d. locationAreaCode = %d. cellId = %d. " % (rotateDegreesImage, mobileCountryCode, mobileNetworkCode, locationAreaCode, cellId)
    except:
        if (MY_DEBUG_STDOUT):
            print "Exception in GetTextForState(cameraId = %d)..." % (cameraId)
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

    return resText


#Upload file from local filesystem to the server.
def UploadFile(pathFileName, inetServerAddress, pageOnServer): #!!TODO: I should take out params inetServerAddress and pageOnServer.
    global deviceId

    if (MY_DEBUG_STDOUT):
        print "Entered UploadFile()."
        sys.stdout.flush()
    #See http://docs.python.org/library/struct.html
    myFormat = "<256s" #(32 bits long??) integers, in little endian format. IMPORTANT NOTE: we use "<" to specify ALSO no alignment - see http://docs.python.org/library/struct.html

    dataHeader = struct.pack(myFormat, pathFileName)
    sizeDataHeader = len(dataHeader)
    dataHeader = struct.pack("<i", sizeDataHeader) + dataHeader #IMPORTANT NOTE: we use "<" to specify little endian and no alignment - see http://docs.python.org/library/struct.html

    try:
        """
        Read the binary file from disk in chunks, and compress with Zlib using stream aware compress objects - see 
            http://docs.python.org/library/zlib.html and 
            http://stackoverflow.com/questions/2423866/python-decompressing-gzip-chunk-by-chunk/2424549#2424549 for details.
        """
        #myData = ""

        myBufferSize = 64 * 1024
        zlibCompressObject = zlib.compressobj(1) #1 = lowest compression

        #myBuffer = struct.pack("100s", deviceId) + dataHeader
        myBuffer = AddPacketHeader(dataHeader)
        myData = zlibCompressObject.compress(myBuffer)

        fInput = open(pathFileName, "rb")
        while (True):
            myBuffer = fInput.read(myBufferSize)
            if (len(myBuffer) == 0):
                break
            myData += zlibCompressObject.compress(myBuffer)
        fInput.close()

        myData += zlibCompressObject.flush()

        """
        fInput = open(pathFileName, "rb")
        myData = fInput.read()
        fInput.close()
        """

        #myData = dataHeader + myData
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, "Exception in UploadFile with pathFileName = %s - details: free_ram = %d. %s. Bailing out..." % ( pathFileName, GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)) ), PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

        if (MY_DEBUG_STDOUT):
            print "Exception in UploadFile with pathFileName = %s. Bailing out..." % (pathFileName)
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
        return

    try:
        fileName = os.path.split(pathFileName)[1] #This returns the basename of the file - I think os.path.basename() is not supported on PyS60.
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
    return UploadBinaryData(myData, inetServerAddress, pageOnServer, fileName)
    #return UploadGZippedData(deviceId, myData, inetServerAddress, pageOnServer, fileName)


lastiOSTakePicturePhotoPathFileName = None
#Take photo at specified resolution, save it and scale it to the desired resolution and send it.
def TakePhotoAndUpload(cameraId):
    global accessPointName, bluetoothMode
    global LOCAL_FOLDER_MEDIA_FILES
    global photoModeStr, localPhotoResolution, flashStr, exposureStr, whiteBalanceStr
    global photoModeIndex, digitalZoom, flashIndex, exposureIndex, whiteBalanceIndex
    global deviceId
    global orientationForThisPhoneModel

    GetGSMLocation()

    #t = datetime.datetime.now()
    #photoFileName = t.strftime("%Y_%m_%d_%H_%M_%S.jpg") #see http://pleac.sourceforge.net/pleac_python/datesandtimes.html and http://docs.python.org/library/time.html#time.strftime for details
    """
    crtTime = GetCurrentDateTime()
    photoFileName = time.strftime("%Y_%m_%d_%H_%M_%S", crtTime) + ("_%d.png" % cameraId)
    photoModeIndex[0] = 2 #RGB24
    """

    photoFileName = GetCurrentDateTimeStringWithMilliseconds() + ("_%d.jpg" % cameraId)
    #photoFileName = time.strftime("%Y_%m_%d_%H_%M_%S", crtTime) + ("_%d.jpg" % cameraId)
    if (storeLocallyMedia == 0):
        pass
    else:
        photoPathFileName = LOCAL_FOLDER_MEDIA_FILES + "/" + photoFileName

    myText  = "TakePhotoAndUpload(%d) with photoPathFileName = %s: localPhotoResolution[cameraId] = %s, photoMode[cameraId] = %s. " % (cameraId, photoPathFileName, str(localPhotoResolution[cameraId]), photoModeStr[photoModeIndex[cameraId]][1])
    myText += GetTextForState(cameraId)
    if (MY_DEBUG_STDOUT):
        print myText
        sys.stdout.flush()

    if (iOS_PYOBJC):
        try:
            """
            #From http://www.telesphoreo.org/pipermail/iphone-python/2008-September/000126.html
                "This is actually fairly simple with the PhotoLibrary framework. I don't know how to do it offhand, but it pretty much has messages for "take a picture to disk". -J"
                "UIImagePickerController doesn't let you take a picture and save it to disk, AFAIK it only lets you ask the user to choose a picture and optionally take one instead. -J"

            http://forums.macrumors.com/showthread.php?t=462326
                Reference to https://code.google.com/p/iflickr/source/browse/trunk/bkp/PhotoLibrary.h?r=10
                "i dont know if this is what you mean but i was able to get the same video ability as on the normal unjailbroken 3gs on my 3g by copying the photolibrary.framework file folder from a 3gs and paste it on my 3g at /var/system/library/privateframeworks. im sure you can figure something out by knowing this "

            Camera APIs
                http://forums.macrumors.com/showthread.php?t=462326 - unofficial camera APIs
                http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html
                    "Check which media types are available, for the source type youre using, by calling the availableMediaTypesForSourceType: class method. This lets you distinguish between a camera that can be used for video recording and one that can be used only for still images."
                http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/CameraAndPhotoLib_TopicsForIOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010400
                http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40010188-CH1-SW10
            """

            """
            !!!! Use lock/mutex to synchronize with the takePicture "loop".
            """

            #cameraCapturePicture(photoPathFileName)
            #time.sleep(5.0) #Wait a bit to make sure the photo gets saved.
            #SleepAndPetWatchdog(5.0, False)

            if (lastiOSTakePicturePhotoPathFileName == None):
                if (MY_DEBUG_STDOUT):
                    print "TakePhotoAndUpload(%d): lastiOSTakePicturePhotoPathFileName == None --> bailing out." % (cameraId)
                    sys.stdout.flush()
                return

            photoPathFileName = lastiOSTakePicturePhotoPathFileName
            photoFileName = os.path.basename(photoPathFileName)
            res = UploadStateAndFileAndStoreState(deviceId, photoFileName, photoPathFileName, cameraId, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE, singleThreaded = True)
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

    #!!!!Optimize: make more checks and erase the file earlier, and maybe don't even save the local file if really not needed.
    if (storeLocallyMedia == 0):
        try:
            os.unlink(photoPathFileName)
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()


def VideoRecordCallback(errorCode, eventType):
    pass


def SetViewFinderSizeForVideoRecording(cameraId):
    global viewFinderSize, localVideoMode
    global deviceId

    if (localVideoMode[cameraId][0][0] >= 320):
        viewFinderSize = (293, 240) #This is conserving aspect ratio for (320, 240), as for (176, 144)
    else:
        viewFinderSize = localVideoMode[cameraId][0]


def VideoRecordAndUpload(cameraId, recordDuration):
    global accessPointName#, bluetoothMode
    global LOCAL_FOLDER_MEDIA_FILES, deviceId
    global viewFinderSize
    global videoLock

    if (MY_DEBUG_STDOUT):
        myText  = "Entered VideoRecordAndUpload() at %s." % GetCurrentDateTimeStringNice()
        print myText
        sys.stdout.flush()

    GetGSMLocation()

    #crtTime = GetCurrentDateTime()
    #videoFileName = time.strftime("%Y_%m_%d_%H_%M_%S", crtTime) + ("_%d.3gp" % cameraId) #see http://pleac.sourceforge.net/pleac_python/datesandtimes.html and http://docs.python.org/library/time.html#time.strftime for details
    videoFileName = GetCurrentDateTimeStringWithMilliseconds() + ("_%d.3gp" % cameraId)
    if (storeLocallyMedia == 0):
        pass
    else:
        videoPathFileName = LOCAL_FOLDER_MEDIA_FILES + "/" + videoFileName

    if (MY_DEBUG_STDOUT):
        myText  = "VideoRecordAndUpload(%d) with videoFileName = %s, videoPathFileName = %s, recordDuration = %d, localVideoMode[cameraId] = %s. " % (cameraId, videoFileName, videoPathFileName, recordDuration, str(localVideoMode[cameraId]))
        myText += GetTextForState(cameraId)
        print myText
        sys.stdout.flush()

    #!!!!To implement video recording on iOS

    #res = UploadStateAndFileAndStoreState(deviceId, videoFileName, OUTPUT_VIDEO_PATH_FILENAME, cameraId, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE)
    res = UploadStateAndFileAndStoreState(deviceId, videoFileName, videoPathFileName, cameraId, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE, singleThreaded = False)

    if (storeLocallyMedia == 0):
        if (MY_DEBUG_STDOUT):
            print "VideoRecordAndUpload(): Since storeLocallyMedia == 0, now I erase it (note that on S60 I saved the movie on D:)."
            sys.stdout.flush()


MULTITHREADED_VIDEORECORD_AND_UPLOAD = True
def VideoRecordAndUploadBurstMode(cameraId, recordDuration):
    global accessPointName#, bluetoothMode
    global LOCAL_FOLDER_MEDIA_FILES, deviceId
    global viewFinderSize
    global videoLock

    global uploadUnsentData
    uploadUnsentData = 0

    #We save the unsent packet in the ram drive.
    #In fact we should not even save the Unsent packets - simply drop them maybe
    #LOCAL_FOLDER_UNSENT_FILES = "D:/Unsent"
    LOCAL_FOLDER_UNSENT_FILES = LOCAL_FOLDER_TEMP + "/Unsent"
    if not os.path.exists(LOCAL_FOLDER_UNSENT_FILES):
        os.makedirs(LOCAL_FOLDER_UNSENT_FILES)

    if (MY_DEBUG_STDOUT):
        myText  = "Entered VideoRecordAndUploadBurstMode() at %s." % GetCurrentDateTimeStringNice()
        print myText
        sys.stdout.flush()

    if (orientationForThisPhoneModel == "landscape"):
    #if (phoneModel in ["Nokia6120", "NokiaN95", "NokiaN82"]):
        isBackLightOn = True
    else:
        isBackLightOn = False

    pass


def AudioRecordAndUpload(recordDuration):
    global LOCAL_FOLDER_MEDIA_FILES, accessPointName, deviceId

    #crtTime = GetCurrentDateTime()
    #audioFileName = time.strftime("%Y_%m_%d_%H_%M_%S.amr", crtTime) #see http://pleac.sourceforge.net/pleac_python/datesandtimes.html and http://docs.python.org/library/time.html#time.strftime for details
    audioFileName = GetCurrentDateTimeStringWithMilliseconds() + ".amr"
    if (storeLocallyMedia == 0):
        #audioPathFileName = "D:/iCamTemp.amr" #Since we don't want to store the file, we save in the RAM drive.
        audioPathFileName = LOCAL_FOLDER_TEMP + "/iCamTemp.amr" #Since we don't want to store the file, we save in the RAM drive.
    else:
        audioPathFileName = LOCAL_FOLDER_MEDIA_FILES + "/" + audioFileName

    if (MY_DEBUG_STDOUT):
        myText = "AudioRecordAndUpload() with audioFileName = %s and recordDuration = %d. " % (audioFileName, recordDuration)
        myText += GetTextForState(0)
        print myText
        sys.stdout.flush()
    
    try:
        audioPathFileNameWithBackslashes = audioPathFileName.replace("/", "\\") #Requires backslashes, otherwise audio.Sound.open() PROBABLY does not create any file.
        mySound = audio.Sound.open(audioPathFileNameWithBackslashes)
        mySound.record()
        SleepAndPetWatchdog(recordDuration, False)
        #e32.ao_sleep(recordDuration)
        mySound.stop()
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        errorStr = "AudioRecordAndUpload() with audioFileName %s (free_ram = %d) returned exception %s. Bailing out..." % (audioFileName, GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)))
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, errorStr, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
        if (MY_DEBUG_STDOUT):
            print errorStr
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.write("    " + errorStr + "\n")
            sys.stderr.flush()
        return

    #if (accessPointName == u""):
    #    print "AudioRecordAndUpload(): Not uploading movie."
    #    sys.stdout.flush()
    #    return

    res = UploadStateAndFileAndStoreState(deviceId, audioFileName, audioPathFileName, 2, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE, singleThreaded = True) #We make cameraId = 2.

    if (storeLocallyMedia == 0):
        print "Since storeLocallyMedia == 0, I saved the audio file on D: and now I erase it."
        sys.stdout.flush()
        try:
            """
            if (SYMBIAN_OS and (pyS60VersionNumber > 14)):
                mediaUploadedLock.wait()
            """
            os.unlink(audioPathFileName)
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()


def CompareTimesOfDay(timeOfDay1, timeOfDay2):
    #timeOfDay = (hour, min, sec, ...).
    #Returns True if timeOfDay1 > timeOfDay2, else False.
    if (timeOfDay1[0] < timeOfDay2[0]):
        return False
    if (timeOfDay1[0] > timeOfDay2[0]):
        return True

    if (timeOfDay1[1] < timeOfDay2[1]):
        return False
    if (timeOfDay1[1] > timeOfDay2[1]):
        return True

    if (timeOfDay1[2] < timeOfDay2[2]):
        return False
    if (timeOfDay1[2] > timeOfDay2[2]):
        return True


def ModeManager():
    global videoRecordDuration
    global dawnTimeVec, duskTimeVec
    #return

    crtTime = GetCurrentDateTime()
    if (CompareTimesOfDay([crtTime.tm_hour, crtTime.tm_min, crtTime.tm_sec], dawnTimeVec) and (CompareTimesOfDay(duskTimeVec, [crtTime.tm_hour, crtTime.tm_min, crtTime.tm_sec]))):
    #Day mode
        if (MY_DEBUG_STDOUT):
            print "ModeManager(): Day mode - calling SetRecordDuration(0, 0)."
            sys.stdout.flush()
        """
        """
        if (videoRecordDuration[0] != 0): #To avoid setting too often - it stores state on drive.
            SetRecordDuration(0, 0)
            #SetRecordDuration(1, 0)
    else:
    #Night mode
        if (MY_DEBUG_STDOUT):
            print "ModeManager(): Night mode - calling SetRecordDuration(0, 15)."
            sys.stdout.flush()
        if (videoRecordDuration[0] == 0): #To avoid setting too often - it stores state on drive.
            SetRecordDuration(0, 15)


def GetBatteryLevelPercentage():
    try:
        if (iOS_PYOBJC):
            return 100
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def GetChargerStatusStr():
    global sysagentImported

    if (iOS_PYOBJC):
        return "[N/A]"


def GetChargerStatus():
    global deviceId, sysagentImported

    if (iOS_PYOBJC):
        return 1


def PowerManager():
    global pauseInterval
    global conserveEnergy, uploadUnsentData

    """
    EChargingStatusError              = -1,
    EChargingStatusNotConnected       = 0,  /// Charger not connected/uninitialized
    EChargingStatusCharging           = 1,  /// Device is charging
    EChargingStatusNotCharging        = 2,  /// Charger is connected, device not charging
    EChargingStatusAlmostComplete     = 3,  /// Charging almost completed
    EChargingStatusChargingComplete   = 4,  /// Charging completed
    EChargingStatusChargingContinued  = 5   /// Charging continued after brief interruption
    if (GetChargerStatus() == 0):
        #Conserve energy
    elif (GetChargerStatus() == 1,5):
        #Conserve energy somewhat.
    elif (GetChargerStatus() == 2):
        #Go for maximum performance.
    elif (GetChargerStatus() == 3, 4):
        pass
    """

    try:
        crtGetBatteryLevelPercentage = float(GetBatteryLevelPercentage())
        crtGetChargerStatus = GetChargerStatus()

        pauseIntervalPowerManaged = pauseInterval
        #Power manage the cellphone - attempt to avoid running out of power
        if (crtGetBatteryLevelPercentage <= BATTERY_LEVEL_THRESHOLD or crtGetChargerStatus == 0):
            #if (deviceId == "356252019503280" or deviceId == "357062005806103" or deviceId == "358064016080560"): #Nokia 6120 and 6680 and N95
            if (deviceId in ["300300300300300"]): #Nokia 6120 and 6680 and N95 and N82
                pauseIntervalPowerManaged = 10 * 60 * 60 #10 hours
                conserveEnergy = True
                #uploadUnsentData = 0
                if (MY_DEBUG_STDOUT):
                    print "PowerManager(): crtGetBatteryLevelPercentage = %f, crtGetChargerStatus = %d --> adjusting pauseIntervalPowerManaged = %d." % (crtGetBatteryLevelPercentage, crtGetChargerStatus, pauseIntervalPowerManaged)
                    sys.stdout.flush()
            """
            !!!!Treat the else case for the above if!!!!!
            """
        else:
            conserveEnergy = False
            #uploadUnsentData = 1
            if (MY_DEBUG_STDOUT):
                print "PowerManager(): crtGetBatteryLevelPercentage = %f, crtGetChargerStatus = %d --> adjusting pauseIntervalPowerManaged = %d." % (crtGetBatteryLevelPercentage, crtGetChargerStatus, pauseIntervalPowerManaged)
                sys.stdout.flush()
        """
        elif (GetBatteryLevelPercentage() <= 50.0):
            pauseInterval = 30 * 60 #30 min
        """
        return pauseIntervalPowerManaged
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def CallbackSMSSend(smsSendState):
    try:
        if (smsSendState == messaging.ESent):
            if (MY_DEBUG_STDOUT):
                print "CallbackSMSSend(smsSendState = %d): Message was sent." % smsSendState
                sys.stdout.flush()
        elif (smsSendState == messaging.ESendFailed):
            if (MY_DEBUG_STDOUT):
                print "CallbackSMSSend(smsSendState = %d): Something went wrong while sending." % smsSendState
                sys.stdout.flush()
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


lastTimeSentMessage = 0 #read it from state.bin!!!!
def CommunicateWithOperator():
    global lastTimeSentMessage

    if (MY_DEBUG_STDOUT):
        print "Entered CommunicateWithOperator()."
        sys.stdout.flush()

    #MAX_TIME_BETWEEN_SEND_MESSAGES = 30 * 24 * 3600 #30 days in seconds
    MAX_TIME_BETWEEN_SEND_MESSAGES = 1 * 24 * 3600 #1 day in seconds

    try:
        if (time.time() - lastTimeSentMessage > MAX_TIME_BETWEEN_SEND_MESSAGES):
            if (MY_DEBUG_STDOUT):
                print "CommunicateWithOperator(): Sending SMS."
                sys.stdout.flush()
            #messaging.sms_send("302", u"") #This returns only if the SMS was sent successfully - the application sometimes gets blocked at .sms_sens()
            messaging.sms_send("302", u"", "7bit", CallbackSMSSend)
            if (MY_DEBUG_STDOUT):
                print "Returned from messaging.sms_send()."
                sys.stdout.flush()
            lastTimeSentMessage = GetCurrentDateTime()
    except:
        if (MY_DEBUG_STDOUT):
            print "CommunicateWithOperator(): returned an exception."
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def ReactiveLoop_real(): #def StoreMediaAndUploadPeriodically():
    #global myTimer
    global pauseIntervalStr, pauseInterval, videoRecordDuration, audioRecordDuration, reactiveLoopIsStarted, burstModeIsStarted
    global modeManagerIsEnabled
    global readGPS
    global startButtonPressed
    global conserveEnergy

    if (MY_DEBUG_STDOUT):
        print "Entered ReactiveLoop()."
        sys.stdout.flush()

    if (startButtonPressed == False):
        startButtonPressed = True

    if (reactiveLoopIsStarted == False):
        burstModeIsStarted = False
        reactiveLoopIsStarted = True
        SetMenu() #We call SetMenu() in order to remove the Start menu item.

    """
    I used after() instead of forever loop with ao_sleep() because I've seen that probably because of the Internet connections to RDS prepaid 
    the forever loop with ao_sleep() was broken and the application was no longer progress(??). That is why  we use after() which invariably 
    progresses (it seems).
    But even the solution with after(), in conditions of stress - BT server with (own and BT client) pauseInterval = 120 had issues with no more progress.
    """
    #if (True):
    while (True):
        if (reactiveLoopIsStarted):
            #EraseOldestMediaFiles()

            if (MY_DEBUG_STDOUT):
                print "Entered ReactiveLoop() iteration."
                sys.stdout.flush()

            if (pauseInterval == 0):
                if (not burstModeIsStarted):
                    if ( (cameraMode[0] != 0) and (cameraMode[1] == 0) ):
                        if (cameraMode[0] == 2): #Burst mode photo
                            StartBurstMode()
                        else: #Video rec
                            if (videoRecordDuration[0] > 0):
                                VideoRecordAndUploadBurstMode(0, videoRecordDuration[0])
                    elif ( (cameraMode[0] == 0) and (cameraMode[1] != 0) ):
                        if (cameraMode[1] == 2): #Burst mode photo
                            StartBurstMode()
                        else: #Video rec
                            if (videoRecordDuration[1] > 0):
                                VideoRecordAndUploadBurstMode(1, videoRecordDuration[1])
                reactiveLoopIsStarted = False
                return
            else:
                hasDownloadedNewCmd = DownloadCommands()

                """
                if (hasDownloadedNewCmd): #DownloadCommands() returns true if reads new commands
                    SetMenu()
                    StoreState()
                """

                """
                This is a tentative implementation of a "watchdog" directly inside iCam as well.
                Especially for Nokia 6680 I appreciate being less likely 
                for iCam to simply crash - but it can run out of memory.
                """
                FREE_RAM_AMOUNT_THRESHOLD = 1 * MEGA_BYTE
                if (GetFreeRAM() < FREE_RAM_AMOUNT_THRESHOLD):
                    print "Free RAM is %d - below %d. Restarting cellphone." % (GetFreeRAM(), FREE_RAM_AMOUNT_THRESHOLD)
                    sys.stdout.flush()
                    RestartPhone()

                """
                   I do this here, because I want to resize the photos received via BT with the latest resolution 
                received from DownloadCommands(). 
                   I should put the BluetoothMessageListProcess() before calling DownloadCommands(), since I want 
                to concentrate all Internet access close, since BluetoothMessageListProcess() takes a lot of time.
                """
                if (bluetoothMode == 1 or bluetoothMode == 2):
                    BluetoothMessageListProcess() #This might take a long time to complete, if there are many BT messages in Inbox.

                """
                if (modeManagerIsEnabled):
                    ModeManager()

                PowerManager()
                """

                #Even if we don't capture anything we still transmit the device's state (GPS if available, GSM, charghing status, free drive space, etc, etc)
                if ((cameraMode[0] == 0) and (cameraMode[1] == 0) and (audioRecordDuration != 0)): # and readGPS):
                    UploadStateAndFileAndStoreState(deviceId, NO_MEDIA_FILE_NAME, NO_MEDIA_FILE_NAME, -1, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_STATE_AND_FILE)

                """
                #We want to distribute the pauseInterval between the cameras, etc.
                pauseIntervalCurrent = 0
                pauseIntervalLeft = pauseInterval
                """

                # For the Main camera:
                if (cameraMode[0] != 0):
                    """
                    if (cameraMode[1] != 0):
                        pauseIntervalCurrent = int(pauseInterval / 2)
                        pauseIntervalLeft -= pauseIntervalCurrent
                    """

                    if ( (cameraMode[0] == 2) or (cameraMode[0] == 3) ):
                        TakePhotoAndUpload(0) 
                    if ( (cameraMode[0] == 1) or (cameraMode[0] == 3) ):
                        if (videoRecordDuration[0] > 0):
                            VideoRecordAndUpload(0, videoRecordDuration[0])

                    """
                    if (pauseIntervalCurrent != 0):
                        try:
                            SleepAndPetWatchdog(pauseIntervalCurrent, True)
                        except:
                            if (MY_DEBUG_STDOUT):
                                print "ReactiveLoop(): sleep returned an exception."
                                sys.stdout.flush()
                            if (MY_DEBUG_STDERR):
                                traceback.print_exc()
                                sys.stderr.flush()
                    """
                    try:
                        SleepAndPetWatchdog(pauseInterval, True)
                    except:
                        if (MY_DEBUG_STDOUT):
                            print "ReactiveLoop(): sleep returned an exception."
                            sys.stdout.flush()
                        if (MY_DEBUG_STDERR):
                            traceback.print_exc()
                            sys.stderr.flush()

                # For the VGA camera:
                if (numCamerasSupported >= 2):
                    if (cameraMode[1] != 0):
                        if ( (cameraMode[1] == 2) or (cameraMode[1] == 3) ):
                            TakePhotoAndUpload(1)
                        if ( (cameraMode[1] == 1) or (cameraMode[1] == 3) ):
                            if (videoRecordDuration[1] > 0):
                                VideoRecordAndUpload(1, videoRecordDuration[1])

                if (audioRecordDuration != 0):
                    AudioRecordAndUpload(audioRecordDuration)

                if (MY_DEBUG_STDOUT):
                    print "Exiting ReactiveLoop()."
                    sys.stdout.flush()

                """
                """
                #In case more Unsent files are available because of transmission errors
                if (uploadUnsentData == 1 or uploadUnsentData == 3):
                    UploadUnsentFILES()

                try:
                    #e32.ao_sleep(pauseInterval)
                    SleepAndPetWatchdog(pauseInterval, True)
                    """
                    SleepAndPetWatchdog(pauseIntervalLeft, True)
                    """
                    #time.sleep(pauseInterval)
                except:
                    if (MY_DEBUG_STDOUT):
                        print "ReactiveLoop(): sleep returned an exception."
                        sys.stdout.flush()
                    if (MY_DEBUG_STDERR):
                        traceback.print_exc()
                        sys.stderr.flush()


def ReactiveLoop():
    ReactiveLoop_real()
    #thread.start_new_thread(ReactiveLoop_real, ())
    #MyThreadStart(ReactiveLoop_real)


def StopBroadcasting():
    global reactiveLoopIsStarted
    global startButtonPressed

    pass


def ReactiveLoopOnlyIfStartButtonNotAlreadyPressed():
    global startButtonPressed
    global reactiveLoopIsStarted

    pass


def ReactiveLoopStop():
    global reactiveLoopIsStarted, startButtonPressed
    reactiveLoopIsStarted = False
    #startButtonPressed = False
    #DisplayNote("Stopped.")


serversFormSaved = False #This var is required as a global.
def SelectServersMenu():
    global serversFormSaved
    global googleUsername, googlePassword, googleRememberPassword
    global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer, googleMediaPrivate, googleKeywords
    global PHP_SERVER_NAME

    #From http://wiki.forum.nokia.com/index.php/How_to_use_Form_in_Python_for_S60 (and also http://www.mobilenin.com/pys60/info_tabs_forms.htm):

    if (googleUsername == None):
        googleUsername = ""

    #Create a list to be used in "combo" selection mode
    yesNoComboList = [u"No", u"Yes"]
    noComboList = [u"No"]
    infoComboList = [u"[Enter When Save Form]"]
    """
    uploadMediaToYouTubeComboList = [u"No", u"Yes"]
    uploadMediaToPicasaComboList  = [u"No", u"Yes"]
    googleRememberPasswordComboList = [u"No", u"Yes"]
    """
    googleMediaPrivateComboList = [u"Public (shared to all)", u"Private (shared only explicitely)"]

    #!!!!to implement

    myFields = [
              #(u"Enter Google YouTube/Picasa login information", "text", u""),
              (u"YouTube/Picasa username", "text", unicode(googleUsername)),
              #(u"YouTube/Picasa password", "text", u"[Enter When Save Form]"), #unicode(GetGooglePassword())), #Enter On Save Form
              (u"YouTube/Picasa password", "combo", (infoComboList, 0)), #unicode(GetGooglePassword())), #Enter On Save Form
              (u"Remember password", "combo", (yesNoComboList, googleRememberPassword)),
              #(u"Password", "code", unicode(googlePassword)), #Gives error: "ValueError: Form field, unknown type"
              (u"Upload to YouTube", "combo", (yesNoComboList, uploadMediaToYouTube)),
              (u"Upload to Picasa", "combo", (yesNoComboList, uploadMediaToPicasa)),
              #(u"Upload to iCam server", "combo", (yesNoComboList, uploadMediaToiCamServer)),
              (u"Upload media to iCam Server", "combo", (noComboList, uploadMediaToiCamServer)),
              (u"Media permissions on YouTube/Picasa", "combo", (googleMediaPrivateComboList, googleMediaPrivate)),
              (u"YouTube video keywords", "text", unicode(googleKeywords)),
              (u"iCam Server address", "text", unicode(PHP_SERVER_NAME))
              #(u"Permissions of uploaded media on YouTube/Picasa:", "combo", (googleMediaPrivateComboList, 0))
              #(u"Amount", "number", 5),
              #(u"Date", "date"),
              #(u"Time","time")
             ]

    if (MY_DEBUG_STDOUT):
        try:
            print "SelectServersMenu(): at the end"
            print "    googleUsername =", googleUsername
            #print "    googlePassword =", googlePassword
            print "    googleRememberPassword =", googleRememberPassword
            print "    uploadMediaToYouTube =", uploadMediaToYouTube
            print "    uploadMediaToPicasa =", uploadMediaToPicasa
            print "    googleMediaPrivate =", googleMediaPrivate
            print "    googleKeywords =", googleKeywords
            sys.stdout.flush()
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()
    #"""


miscFormSaved = False #This var is required as a global.
def MiscellaneousSettingsMenu():
    global miscFormSaved
    global startAutomatically, readGPS, storeLocallyMedia, LOCAL_FOLDER
    global numThreadsUpload
    global MY_DEBUG_STDOUT, MY_DEBUG_STDERR, MY_DEBUG_STDERR_2, MY_DEBUG_UPLOAD_MSG

    #Create a list to be used in "combo" selection mode
    yesNoComboList = [u"No", u"Yes"]
    noComboList = [u"No"]

    myFields = [
                (u"Start broadcasting automatically", "combo", (yesNoComboList, startAutomatically)),
                (u"Store Locally", "combo", (yesNoComboList, storeLocallyMedia)),
                (u"iCam Folder", "text", unicode(LOCAL_FOLDER)),
                (u"Number of upload threads for burst mode", "number", numThreadsUpload),
                (u"Debug logging", "combo", (yesNoComboList, MY_DEBUG_STDOUT or MY_DEBUG_STDERR or MY_DEBUG_STDERR_2 or MY_DEBUG_UPLOAD_MSG))
                #add Log: MY_DEBUG_*!!!!
               ]

    #!!!!to implement

    if (MY_DEBUG_STDOUT):
        try:
            print "MiscellaneousSettingsMenu(): at the end"
            print "    startAutomatically =", startAutomatically
            print "    readGPS =", readGPS
            sys.stdout.flush()
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()


analysisFormSaved = False #This var is required as a global.
def MediaAnalysisMenu():
    global analysisFormSaved
    #global burstModeIsStarted
    global motionDetectionIsOn

    #Create a list to be used in "combo" selection mode
    yesNoComboList = [u"No", u"Yes"]
    noComboList = [u"No"]

    myFields = [
                (u"Use Motion Detection for Photo Burst Mode", "combo", (yesNoComboList, motionDetectionIsOn))
               ]

    #!!!!to implement



def SelectPresetMainVideoRecord():
    global cameraMode, videoRecordDuration, readGPS, pauseInterval, localPhotoResolutionIndex, photoResolutionIndex
    global videoAudioEnabled, localVideoModeIndex, storeLocallyMedia

    cameraMode[0] = 1
    cameraMode[1] = 0
    #videoRecordDuration[0] = 30
    readGPS = 0
    pauseInterval = 120
    #localPhotoResolutionIndex[0] = 0
    #photoResolutionIndex = 1 #"Use Local Resolution"
    videoAudioEnabled = 1
    #localVideoModeIndex = !!!!!!!!!!!!!
    storeLocallyMedia = 1

    StoreState()


def SelectPresetMainTakePhoto():
    global cameraMode, videoRecordDuration, readGPS, pauseInterval, localPhotoResolutionIndex, photoResolutionIndex
    global videoAudioEnabled, localVideoModeIndex, storeLocallyMedia

    cameraMode[0] = 2
    cameraMode[1] = 0
    #videoRecordDuration[0] = 30
    readGPS = 0
    pauseInterval = 120
    #localPhotoResolutionIndex[0] = 0
    photoResolutionIndex = 1 #"Use Local Resolution"
    videoAudioEnabled = 1
    #localVideoModeIndex = !!!!!!!!!!!!!
    storeLocallyMedia = 1

    StoreState()


def SelectPresetMainBurstPhotos():
    global cameraMode, videoRecordDuration, readGPS, pauseInterval, localPhotoResolutionIndex, photoResolutionIndex
    global videoAudioEnabled, localVideoModeIndex, storeLocallyMedia
    global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer

    cameraMode[0] = 2
    cameraMode[1] = 0
    #videoRecordDuration[0] = 30
    readGPS = 0
    pauseInterval = 0 #!!!!!!!!!!!!
    #localPhotoResolutionIndex[0] = 0
    photoResolutionIndex = 4 #160x120; 6 = 320x240
    #videoAudioEnabled = 1
    #localVideoModeIndex = !!!!!!!!!!!!!

    #storeLocallyMedia = 1

    StoreLocalStateInFile()
    StoreState()


def SelectPresetMainBurstVideos():
    global cameraMode, videoRecordDuration, readGPS, pauseInterval, localPhotoResolutionIndex, photoResolutionIndex
    global videoAudioEnabled, localVideoModeIndex, storeLocallyMedia
    global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer

    cameraMode[0] = 1
    cameraMode[1] = 0
    #videoRecordDuration[0] = 30
    readGPS = 0
    pauseInterval = 0 #!!!!!!!!!!!!
    #localPhotoResolutionIndex[0] = 0
    #photoResolutionIndex = 4 #160x120; 6 = 320x240
    #videoAudioEnabled = 1
    #localVideoModeIndex = !!!!!!!!!!!!!

    #storeLocallyMedia = 1

    StoreLocalStateInFile()
    StoreState()


def SetMenu(firstTime = False):
    global pauseIntervalStr, photoResolutionStr, phoneModel, deviceId
    global readGPS
    global numCamerasSupported
    global menuTable
    global startButtonPressed

    if (MY_DEBUG_STDOUT):
        print "Entered SetMenu()."
        sys.stdout.flush()

    pass #!!!!

    if (MY_DEBUG_STDOUT):
        print "Exiting SetMenu()."
        sys.stdout.flush()


def RotSensorCallBack(sensorData):
    #global myCanvas
    #appuifw.Canvas().clear()
    #myCanvas.text((10, 140), u"R: %04d %04d %04d" % (sensorData["data_1"], sensorData["data_2"], sensorData["data_3"]), font = "title", fill = 0xff0000)
    #if (True):
    if (MY_DEBUG_STDOUT):
        print "RotSensor:", sensorData
        #sys.stdout.flush()


try:
    import zipfile
    zipfileImported = True
except:
    zipfileImported = False
    if (MY_DEBUG_STDOUT):
        print "Not able to import the zipfile module."
        sys.stdout.flush()
    if (MY_DEBUG_STDERR):
        traceback.print_exc()
        sys.stderr.flush()
def CheckZipFile(pathFileName):
    #We assume the file exists.

    try:
        if (not zipfile.is_zipfile(pathFileName)):
            myText = "CheckZipFile(): %s is NOT a valid zip file." % pathFileName
            if (MY_DEBUG_STDOUT):
                print myText
                sys.stdout.flush()
            if (MY_DEBUG_UPLOAD_MSG):
                UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
            return -1

        """
        if (MY_DEBUG_STDOUT):
            print "CheckZipFile(): %s is a valid pkzip file." % pathFileName
            sys.stdout.flush()
        """

        #print '-'*40
        #Open the zipped file.
        myZipFile = zipfile.ZipFile(pathFileName, "r")
        if (MY_DEBUG_STDOUT):
            print "CheckZipFile(): The contents of the update ZIP file are:"
            myZipFile.printdir()
            sys.stdout.flush()
        #print '-'*40

        checkFilenameList = ["a.pyc"]
        #Enumerate each archived file and open the manifest.txt .
        for myZipInfo in myZipFile.infolist():
            fileName = myZipInfo.filename
            #checkFilenameList.remove(fileName)
            for indexList in range(len(checkFilenameList)):
                if (checkFilenameList[indexList] == fileName):
                    checkFilenameList.pop(indexList)
            if (fileName == "manifest.txt"):
            #if fname.endswith(".txt"):
                # decompress each file's data
                manifestData = myZipFile.read(fileName)
                print "The contents of %s are:" % fileName
                print manifestData
                #Read manifest.txt to get the update release time and compare it with the current version release time.
                lineList = manifestData.splitlines()
                tokens = lineList[0].split(": ")

                updateReleaseTime = tokens[1]
                if (updateReleaseTime <= CURRENT_RELEASE_TIME):
                    myText = "CheckZipFile(): The installed version of iCam seems to be the most recent one: updateReleaseTime = %s, CURRENT_RELEASE_TIME = %s." % (updateReleaseTime, CURRENT_RELEASE_TIME)
                    if (MY_DEBUG_UPLOAD_MSG):
                        UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
                    if (MY_DEBUG_STDOUT):
                        print myText
                        sys.stdout.flush()
                    return -1
                """
                # save the decompressed data to a new file
                filename = 'unzipped_' + fname
                fout = open(filename, "wb")
                fout.write(data)
                fout.close()
                print "New file created --> %s" % filename
                """
        if (checkFilenameList != []):
            if (MY_DEBUG_STDOUT):
                print "CheckZipFile(): The update ZIP file does not contain the following indicated files:", checkFilenameList
                sys.stdout.flush()
            return -1

        return 0
    except:
        exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
        myText = "Exception in CheckZipFile(). Details: time = %s, free_ram = %d. %s." % (GetCurrentDateTimeStringNice(), GetFreeRAM(), repr(traceback.format_tb(exceptionTraceback)) )
        """
        if (MY_DEBUG_UPLOAD_MSG):
            UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
        """
        if (MY_DEBUG_STDOUT):
            print myText
            sys.stdout.flush()
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            #sys.stderr.write(myText + "\n")
            sys.stderr.flush()
        return -1


def AutoUpdate_real():
    if (MY_DEBUG_STDOUT):
        print "Entered AutoUpdate(): os.getcwd() = %s." % os.getcwd() #os.getcwd() returns the place where lib.zip is installed - e.g., "E:\Private\e21e55ef".
        sys.stdout.flush()

    def ApplyUpdate(UPDATE_PATH_FILENAME, TARGET_UPDATE_PATH_FILENAME, TARGET_UPDATE_PATH_FILENAME_BACKUP):
        if ( (not zipfileImported) or (CheckZipFile(UPDATE_PATH_FILENAME) == 0) ):
            #We check even more for validity of update Zip file, if we can, and if it is OK we apply the update.
            try:
                #if os.path.exists(TARGET_UPDATE_PATH_FILENAME_BACKUP):
                if (os.path.isfile(TARGET_UPDATE_PATH_FILENAME_BACKUP)):
                    os.unlink(TARGET_UPDATE_PATH_FILENAME_BACKUP)
            except:
                if (MY_DEBUG_STDERR):
                    traceback.print_exc()
                    sys.stderr.flush()
            MoveFileBetweenAnyDrives(TARGET_UPDATE_PATH_FILENAME, TARGET_UPDATE_PATH_FILENAME_BACKUP)
            MoveFileBetweenAnyDrives(UPDATE_PATH_FILENAME, TARGET_UPDATE_PATH_FILENAME)
            #CopyFile("E:/private/e21e55ef/lib.zip", "E:/private/e21e55ef/lib_copy.zip")
            myText = "Found update %s. Copied it. Restart app to run updated version." % UPDATE_PATH_FILENAME
            appuifw.note(unicode(myText), "info") 
            if (MY_DEBUG_UPLOAD_MSG):
                UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
            if (MY_DEBUG_STDOUT):
                print myText
                sys.stdout.flush()

    try:
        PetWatchdog()

        #!!!!
        pass
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
def AutoUpdate():
    #AutoUpdate_real()
    #thread.start_new_thread(ReactiveLoop_real, ())
    MyThreadStart(AutoUpdate_real)


def UploadUnsentLogs():
    global LOCAL_FOLDER, MY_DEBUG_STDOUT
    global STDERR_FILENAME_PREFIX, STDOUT_FILENAME_PREFIX
    global stdoutFileName, stderrFileName
    global uploadUnsentData

    hasDownloadedNewCmd = DownloadCommands() #!!!!Maybe check more often

    if (MY_DEBUG_STDOUT):
        #print "Entered UploadUnsentLogs(): uploadUnsentData = %d." % uploadUnsentData
        print "Entered UploadUnsentLogs()."
        sys.stdout.flush()

    """
    if (conserveEnergy or ((uploadUnsentData != 2) and (uploadUnsentData != 3))):
        return
    """

    try:
        if (not os.path.exists(LOCAL_FOLDER_SENT_LOGS)):
            os.makedirs(LOCAL_FOLDER_SENT_LOGS)
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

    try:
        pathFolderName = LOCAL_FOLDER
        folderContent = os.listdir(pathFolderName)
        #sortedFolderContent = sorted(folderContent, reverse = False) #Use reverse = False to send first the oldest ones (like this you send in chronological order). Use reverse = True for sending first the most recent ones.
        folderContent.sort() #sort() without parameters is the ONLY one that works in Python 2.2. (Info on sort at http://wiki.python.org/moin/HowTo/Sorting/.)
        sortedFolderContent = folderContent

        if (MY_DEBUG_STDOUT):
            print "UploadUnsentLogs(): sortedFolderContent = %s." % sortedFolderContent
            sys.stdout.flush()

        for fileName in sortedFolderContent:
            if ( (fileName.find(STDERR_FILENAME_PREFIX) != -1) or (fileName.find(STDOUT_FILENAME_PREFIX) != -1) ):
                if ( (fileName == stdoutFileName) or (fileName == stderrFileName) ): #Since we can't move currently open files we do not process them now.
                    pass
                else:
                    pathFileName = pathFolderName + "/" + fileName
                    #if os.path.isdir(pathFileName):
                    if os.path.isfile(pathFileName):
                        fileSize = os.path.getsize(pathFileName)
                        if (fileSize < 10 * MEGA_BYTE):
                            myText = "UploadUnsentLogs(): sending log file %s of %d bytes at %s." % (fileName, fileSize, GetCurrentDateTimeStringNice())
                            if (MY_DEBUG_STDOUT):
                                print myText
                                sys.stdout.flush()
                            if (MY_DEBUG_UPLOAD_MSG):
                                UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)
                            """
                            if (UploadFile(pathFileName, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_FILE) != -1):
                                if (fileName.find("Watchdog.txt") == -1): #We do not move stdout/stderr_Watchdog.txt files because we want to keep them together for the whole run. But we move stdout/stderr_Watchdog_*.txt
                                    MoveFileBetweenAnyDrives(pathFileName, LOCAL_FOLDER_SENT_LOGS + "/" + fileName)
                            """
                            UploadFile(pathFileName, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_FILE)
                            if (fileName.find("Watchdog.txt") == -1): #We do not move stdout/stderr_Watchdog.txt files because we want to keep them together for the whole run. But we move stdout/stderr_Watchdog_*.txt
                                MoveFileBetweenAnyDrives(pathFileName, LOCAL_FOLDER_SENT_LOGS + "/" + fileName)
                            #break
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()


def GeneralUseCamera(cameraId):
    pass


#For PyObjC
testBedViewControllerInstance = None
NSTimer = None
UIApplicationInstance = None
UIImagePickerControllerInstance = None
UIImagePickerControllerSourceTypeCamera = None

def Main():
    global LOCAL_FOLDER
    global localPhotoResolution, localVideoMode, localQualityIndex
    global photoResolutionStr, photoModeStr, pauseIntervalStr, exposureStr, whiteBalanceStr, flashStr
    global digitalZoom, photoResolutionIndex, localPhotoResolutionIndex, photoModeIndex, photoQuality, pauseInterval, exposureIndex, whiteBalanceIndex, flashIndex
    global audioRecordDuration, videoRecordDuration, rotateDegreesImage
    global mobileCountryCode, mobileNetworkCode, locationAreaCode, cellId #GSM location info
    global signalStrength, signalUnits
    global accessPointName, bluetoothMode
    global gpsInfo, readGPS
    global cameraPhotoSizes_JPEG_Exif, cameraPhotoSizes_RGB24
    global cameraVideoFormats, cameraVideoFrameSizes, cameraVideoModes
    global myMaxRamdriveSize
    global numCamerasSupported
    global deviceId, phoneModel, orientationForThisPhoneModel
    global pyS60VersionNumber
    global bluetoothSelfAddress, bluetoothSelfName
    global accessPointNotConnectedTo
    global startButtonPressed, startAutomatically
    global STATE_FILENAME
    global sensorsAvailable
    global stateLoaded
    global uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer

    #DisplayNote("Testing.")
    phoneModel = GetPhoneModel()

    if (iOS_PYOBJC):
        numCamerasSupported = 1
        cameraPhotoSizes_JPEG_Exif = [[(320,240)], []]
        cameraPhotoSizes_RGB24 = [[(320,240)], []]
        orientationForThisPhoneModel = "portrait"
        sensorsAvailable = ""
        SetMenu(True)

    GetGSMLocation()

    if (iOS_PYOBJC):
        myMaxRamdriveSize = -1
        signalStrength = -1 #!!!!
        signalUnits = "dbm"
        OSName = "iOS"
        accessPointName = u"[DEFAULT_AP]"
        localPhotoResolutionIndex = [-1, -1]

    photoModeIndex = [3, 2]  #JPEG_Exif for Main camera and RGB24 for VGA camera

    if (numCamerasSupported == 1):
        localPhotoResolutionIndex = [0, -1] #the resolution indices for the Main (index 0) and VGA (index 1) camera, pointing at cameraPhotoSizes
    elif (numCamerasSupported == 2):
        #localPhotoResolutionIndex = [0, len(cameraPhotoSizes_RGB24[1]) - 1] #the resolution indices for the Main (index 0) and VGA (index 1) camera, pointing at cameraPhotoSizes
        pass
    if (MY_DEBUG_STDOUT):
        print "Main(): localPhotoResolutionIndex =", localPhotoResolutionIndex
        sys.stdout.flush()

    try:
        if (MY_DEBUG_STDOUT):
            print "Main(): Reading configuration."
            sys.stdout.flush()

        if (LoadStateFromFile(STATE_FILENAME)):
            if (MY_DEBUG_STDOUT):
                print "Main(): Read configuration from %s (or its backup if this file doesn't exist)." % STATE_FILENAME
                sys.stdout.flush()

        else:
            if (MY_DEBUG_STDOUT):
                print "Main(): LoadStateFromFile() returned False."
                sys.stdout.flush()
            #Preserve this order of initializing the state variables
            if (deviceId == INTERNET_PROXY_PHONE_DEVICE_ID):
                if (accessPointName == u""):
                    #accessPointName = u"RDSPP"
                    accessPointName = u"RDS"
                    if (MY_DEBUG_STDOUT):
                        print "Main(): accessPointName is empty so made it %s." % str(accessPointName)
                        sys.stdout.flush()

        LoadStateLocalFromFile(STATE_LOCAL_FILENAME)
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

    stateLoaded = True
    #############################################################################################################################################
    #############################################################################################################################################
    ####We set the bluetoothMode, and also download any commands and execute them ASAP, at the beginning - useful to prevent erroneous modes#####
    #############################################################################################################################################
    #############################################################################################################################################
    if (bluetoothMode == -1):
    #if (bluetoothServerAddress == ""):
        SelectBluetoothMode()
    elif (bluetoothMode == 1): #BluetoothServer
        BluetoothServerInitialize()
    elif (bluetoothMode == 2): #BluetoothClient.
        BluetoothClientDiscoverServer()
        BluetoothClientInitializeInbox()
        BluetoothMessageListProcess() #This (also) has the effect of downloading commands received via BT - equivalent to DownloadCommands().

    SetLocalPhotoResolution()

    """
    accessPointName = u""
    accessPointNotConnectedTo = True
    """
    if (bluetoothMode == 2 or signalStrength == NO_GSM_SIGNAL_STRENGTH):
        if (MY_DEBUG_STDOUT):
            print "Main(): Setting accessPointNotConnectedTo = True."
            sys.stdout.flush()
        accessPointNotConnectedTo = True
    else:
        #We can choose a WiFI or 3G Acess Point:
        SelectAccessPointIfNoneAvailableAndConnectToIt()

    ##############################################################################################################################
    ##############################################################################################################################
    #################################NOW PHONE SHOULD HAVE CONNECTIVITY - 3G and/or Bluetooth#####################################
    ###########IMPORTANT: DO NOT UPLOAD OR DOWNLOAD ANYTHING BEFORE HERE, BECAUSE IT MIGHT POP A MENU ASKING FOR ACCESS POINT#####
    ##############################################################################################################################

    if (bluetoothMode != 2):
        DownloadCommands()
        #thread.start_new_thread(DownloadCommmandsThread, ())
        #MyThreadStart(DownloadCommands)

    #myText1 = "Started application on %s." % datetime.datetime.now().ctime()
    try:
        myText = "<br/><br/>\nStarted application on %s - %s version. Release time: %s.\n" % (GetCurrentDateTimeStringNice(), OSName, CURRENT_RELEASE_TIME)
        myText += "deviceId = %s. phoneNumber = %s. " % (deviceId, phoneNumber)
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
    try:
        myText += "sys.platform = %s." % sys.platform
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
    try:
        myText += "bluetoothSelfAddress = %s. bluetoothSelfName = %s. bluetoothMode = %d. \n" % (bluetoothSelfAddress, bluetoothSelfName, bluetoothMode)
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()
    try:
        myText += "pauseInterval = %d. pauseIntervalBetweenGoogleGdataMediaUploads = %d. numCamerasSupported = %d. cameraMode[0] = %d. cameraMode[1] = %d. orientationForThisPhoneModel = %s. \n" % (pauseInterval, pauseIntervalBetweenGoogleGdataMediaUploads, numCamerasSupported, cameraMode[0], cameraMode[1], orientationForThisPhoneModel)
        if (numCamerasSupported > 0):
            pass
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

    localVideoMode = [((176, 144), 15.0), ((176, 144), 15.0)] #Every Symbian phone should support this resolution.

    try:
        cameraVideoFormats[0] = []
        cameraVideoFrameSizes[0] = [(176, 144)]
        cameraVideoModes[0] = [{"rate": 15.0, "size": (176, 144)}]
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

    try:
        myText += "battery = %d. charger_status = %d. \n" % (GetBatteryLevelPercentage(), GetChargerStatus())
        myText += "MY_DEBUG_STDOUT = %d, MY_DEBUG_STDERR = %d, MY_DEBUG_STDERR_2 = %d, MY_DEBUG_UPLOAD_MSG = %d. \n" % (MY_DEBUG_STDOUT, MY_DEBUG_STDERR, MY_DEBUG_STDERR_2, MY_DEBUG_UPLOAD_MSG)
        myText += "LOCAL_FOLDER = %s, LOCAL_FOLDER_MEDIA_FILES = %s. STDOUT file name = %s. STDERR file name = %s. " % (LOCAL_FOLDER, LOCAL_FOLDER_MEDIA_FILES, stdoutFileName, stderrFileName)
        myText += "uploadMediaToYouTube = %d, uploadMediaToPicasa = %d, uploadMediaToiCamServer = %d. " % (uploadMediaToYouTube, uploadMediaToPicasa, uploadMediaToiCamServer)
        myText += "QoS params: storeLocallyMedia = %d, SOCKET_DEFAULT_TIMEOUT = %.2f, uploadUnsentData = %d, uploadHowManyOfLatestBluetoothMessages = %d, ERASE_ORIGINAL_MEDIA_FILE_AFTER_READ = %d. " % (storeLocallyMedia, SOCKET_DEFAULT_TIMEOUT, uploadUnsentData, uploadHowManyOfLatestBluetoothMessages, ERASE_ORIGINAL_MEDIA_FILE_AFTER_READ)
        myText += "PHP_SERVER_NAME = %s.\n" % (PHP_SERVER_NAME)
        myText += "BATTERY_LEVEL_THRESHOLD = %d.\n" % (BATTERY_LEVEL_THRESHOLD)        
        myText += "localPhotoResolution = %s.\n" % str(localPhotoResolution)
        myText += "localVideoMode = %s; localVideoModeIndex = %s.\n" % (str(localVideoMode), str(localVideoModeIndex))
    except:
        if (MY_DEBUG_STDERR):
            traceback.print_exc()
            sys.stderr.flush()

    if (MY_DEBUG_STDOUT):
        print myText
        sys.stdout.flush()

    if (MY_DEBUG_UPLOAD_MSG):
        #UploadText(myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT)
        UploadGZippedData(deviceId, myText, PHP_SERVER_NAME, WEBPAGE_UL_GZIPPED_TEXT, None)

    global STORE_STATE
    STORE_STATE = False
    SetUploadedPhotoResolutionIndex(photoResolutionIndex)()
    SetPhotoQuality(photoQuality)()
    SetPauseInterval(pauseInterval)() #Can take it out, since the implementation does not change anything from the menu.
    #e32.ao_sleep(5)
    SetDigitalZoom(digitalZoom)()

    STORE_STATE = True
    SetMenu()
    StoreState()

    #We put them after "Started application"... - this is more natural, since we want the application to send to server at least "Started"... :)
    AutoUpdate()
    if (pauseInterval != 0):
    #if (pauseInterval != 0 and deviceId != "358064016080560"):
        if (conserveEnergy or ((uploadUnsentData != 2) and (uploadUnsentData != 3))):
            pass
        else:
        #if (conserveEnergy or ((uploadUnsentData != 2) and (uploadUnsentData != 3))):
            UploadUnsentLogs()

    if (deviceId in ["300300300300300"]):
        startAutomatically = True

    if (startAutomatically):
        startButtonPressed = True

    if (iOS_PYOBJC):
        """
        #From https://github.com/erica/iphone-3.0-cookbook-/tree/b8ca8905d17015839a0917e1dcd407d055890236/C07-Images/04-Snapping%20Images

        #import <UIKit/UIKit.h>

        #define COOKBOOK_PURPLE_COLOR   [UIColor colorWithRed:0.20392f green:0.19607f blue:0.61176f alpha:1.0f]
        #define BARBUTTON(TITLE, SELECTOR)  [[[UIBarButtonItem alloc] initWithTitle:TITLE style:UIBarButtonItemStylePlain target:self action:SELECTOR] autorelease]
        #define SETIMAGE(X) [(UIImageView *)self.view setImage:X];
        #define showAlert(format, ...) myShowAlert(__LINE__, (char *)__FUNCTION__, format, ##__VA_ARGS__)

        // Simple Alert Utility
        void myShowAlert(int line, char *functname, id formatstring,...)
        {
            va_list arglist;
            if (!formatstring) return;
            va_start(arglist, formatstring);
            id outstring = [[[NSString alloc] initWithFormat:formatstring arguments:arglist] autorelease];
            va_end(arglist);
            
            NSString *filename = [[NSString stringWithCString:__FILE__ encoding:NSUTF8StringEncoding] lastPathComponent];
            NSString *debugInfo = [NSString stringWithFormat:@"%@:%d\n%s", filename, line, functname];
            
            UIAlertView *av = [[[UIAlertView alloc] initWithTitle:outstring message:debugInfo delegate:nil cancelButtonTitle:@"OK"otherButtonTitles:nil] autorelease];
            [av show];
        }

        @interface TestBedViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate>
        @end

        @implementation TestBedViewController
        - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo; 
        {
            if (!error) 
                showAlert(@"Image written to photo album");
            else
                showAlert(@"Error writing to photo album: %@", [error localizedDescription]);
        }

        - (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
        {
            UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
            SETIMAGE(image);
            UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
            [self dismissModalViewControllerAnimated:YES];
            [picker release];
        }

        // Provide 2.x compliance
        - (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo
        {
            NSDictionary *dict = [NSDictionary dictionaryWithObject:image forKey:@"UIImagePickerControllerOriginalImage"];
            [self imagePickerController:picker didFinishPickingMediaWithInfo:dict];
        }

        // Optional but "expected" dismiss
        /*
        - (void) imagePickerControllerDidCancel: 
        (UIImagePickerController *)picker
        {
            [self dismissModalViewControllerAnimated:YES];
            [picker release];
        }
        */

        - (void) snapImage: (id) sender
        {
            UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
            ipc.sourceType =  UIImagePickerControllerSourceTypeCamera;
            ipc.delegate = self;
            ipc.allowsImageEditing = NO;
            [self presentModalViewController:ipc animated:YES]; 
        }

        - (void) viewDidLoad
        {
            self.navigationController.navigationBar.tintColor = COOKBOOK_PURPLE_COLOR;
            if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
                    self.navigationItem.rightBarButtonItem = BARBUTTON(@"Snap", @selector(snapImage:));
            else
                showAlert(@"This demo relies on camera access, which is not available on this system. Please run this application on a camera-ready device.");
            self.title = @"Image Picker";
        }
        @end

        @interface TestBedAppDelegate : NSObject <UIApplicationDelegate>
        @end

        @implementation TestBedAppDelegate
        - (void)applicationDidFinishLaunching:(UIApplication *)application {    
            UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
            UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[[TestBedViewController alloc] init]];
            [window addSubview:nav.view];
            [window makeKeyAndVisible];
        }
        @end

        int main(int argc, char *argv[])
        {
            NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
            int retVal = UIApplicationMain(argc, argv, nil, @"TestBedAppDelegate");
            [pool release];
            return retVal;
        }
        """

        try:
            """
            if (MY_DEBUG_STDOUT):
                #print "Main: preparing to use UIImagePickerController."
                print "Main: preparing to take photo."
                sys.stdout.flush()
            """

            #myNSTimer = NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(5.0, testBedViewControllerInstance, objc.selector(testBedViewControllerInstance.MyIPC, signature = "v@:"), objc.nil, objc.NO)
            #testBedViewControllerInstance.MyIPC() #Doesn't show viewfinder --> doesn't call the delegates...
            #testBedViewControllerInstance.TimedCallMyIPC() #NSTimer doesn't work... --> takePicture() is not called, NOTHING is called...


            """
            #From https://code.google.com/p/py-iphone-toolkits/source/browse/trunk/PyIPhone/UIKit.py
            class NSObject:
                #summary:
                #    NSObject is the root class of most Objective-C class hierarchies. Through NSObject, objects 
                #    inherit a basic interface to the runtime system and the ability to behave as Objective-C objects.
                #    
                #see:
                #    http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/cl/NSObject
                
                def __init__(self):
                    #summary:
                    #    Initializes the object. It creates the base variable to hold the Objective-C object to wrap.
                    self.__internalObject__ = None

            class UIViewController(NSObject):
                def __init__(self):
                    #Initialize Super Class
                    NSObject.__init__(self)

            class UINavigationController(UIViewController):
                def __init__(self):
                    #Initialize Super Class
                    UIViewController.__init__(self)

            class UIImagePickerController(UINavigationController):
                def __init__(self):
                    #Initialize Super Class
                    UINavigationController.__init__(self)
            """

            #import UIImagePickerController #Doesn't work

            ReactiveLoop()




            #[self presentModalViewController:ipc animated:YES]
            #self.presentModalViewController_animated_(ipc, True)
            #UIApplicationInstance.presentModalViewController_animated_(ipc, objC.YES) #AttributeError: 'PYApplication' object has no attribute 'presentModalViewController_animated_'
            #Not good I think: self.presentModalViewController_(ipc) #self.animated_(True)
        except:
            if (MY_DEBUG_STDERR):
                traceback.print_exc()
                sys.stderr.flush()

        #ReactiveLoop()


#######################################################################################################################
#######################################################################################################################
#######################################################################################################################
###########################################PROGRAM Main()##############################################################
#######################################################################################################################
#######################################################################################################################
def DisplayInfo(displayMode = 1, displayAllInfo = True):
    global doNotDisplayRedrawInfo
    global canvas

    pass


"""
The execfile() has to be issued in the "global space" (i.e., outside functions) - otherwise the function and variable redefinition might not work - 
    probably because of "execfile() cannot be used reliably to modify a function's locals" (see below).
From http://docs.python.org/library/functions.html#execfile.
Note:
    The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. 
    Pass an explicit locals dictionary if you need to see effects of the code on locals after function execfile() returns.
    execfile() cannot be used reliably to modify a function's locals.
"""
EXTENSION_MOTION_DETECTION_SCRIPT_FILENAME = "iCam_MD.py"
EXTENSION_MOTION_DETECTION_SCRIPT_PATH_FILENAME = LOCAL_FOLDER + "/" + EXTENSION_MOTION_DETECTION_SCRIPT_FILENAME
try:
    #if os.path.exists(EXTENSION_MOTION_DETECTION_SCRIPT_PATH_FILENAME):
    if os.path.isfile(EXTENSION_MOTION_DETECTION_SCRIPT_PATH_FILENAME):
        if (MY_DEBUG_STDOUT):
            print "Found %s. Loading it." % EXTENSION_MOTION_DETECTION_SCRIPT_PATH_FILENAME
            sys.stdout.flush()
        execfile(EXTENSION_MOTION_DETECTION_SCRIPT_PATH_FILENAME)
        if (MY_DEBUG_STDOUT):
            print "numHotspots = %d." % numHotspots
            sys.stdout.flush()
except:
    if (MY_DEBUG_STDOUT):
        print "execfile(%s) returned exception." % EXTENSION_MOTION_DETECTION_SCRIPT_FILENAME
        sys.stdout.flush()
    if (MY_DEBUG_STDERR):
        traceback.print_exc()
        sys.stderr.flush()


#DisplayInfo = -1 #None #It is a function defined later. (I should not define it None)

menuTable = {
    "00Start":     (u"Start Broadcasting", ReactiveLoopOnlyIfStartButtonNotAlreadyPressed,   None,           None), #See http://developer.android.com/reference/android/R.drawable.html for the various icon name strings.
    "00Stop":      (u"Stop Broadcasting",                                StopBroadcasting,   None,           None),
    "01CaptureWhat":            (u"Capture What",                         CaptureWhatMenu,   None,           None),
    #"0Exit":                    (u"Exit",                                            Quit,   None,           None),  #x icon - "ic_delete"
    "0Exit":                    (u"Stop",                                ReactiveLoopStop,   None,           None),  #x icon - "ic_delete"
    #"0Servers":                 (u"YouTube/Picasa",                    SelectServersMenu,   None,           None),
    "0Servers":                 (u"Select Servers",                     SelectServersMenu,   None,           None),
    "Display_Info":             (u"Display Info",                             DisplayInfo,   None,           None),
    "1Pause_Interval":          (u"Pause Interval",                     PauseIntervalMenu,   None,           None), #pencil icon "ic_menu_edit"
    #"1Record_Duration_Main":    (u"Record Config",        SetRecordDurationMenu(0),   None,           None),
    "1Record_Config":           (u"Record Config",                       RecordConfigMenu,   None,           None),
    "Select_BT_Mode":           (u"Bluetooth Intranet",               SelectBluetoothMode,   None,           None),
    "Settings":                 (u"Settings",                                        None,   None,           None), #only used by the PyS60 version
    "Store_Locally":            (u"Store Locally Media",      SelectStoreLocallyMediaMenu,   None,           None)
}


if __name__ == "__main__":
    Main()
